mvc 3 The model item passed into the dictionary is of type A but this dictionary requires a model item of type B - asp.net-mvc-3

I am getting the following error:
The model item passed into the dictionary is of type '...Models.VideoPostingModel', but this dictionary requires a model item of type '...Models.RegisterModel'.
I am not sure what the issue is because the models match up...
Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using stayyolo.Models;
using System.Web.Security;
using System.Data;
...Controllers
{
public class VidsPostingController : Controller
{
private dbEntities db = new dbEntities();
//
// GET: /VidsPosting/
public ActionResult Details(Guid id)
{
Posting posting = db.Postings.Find(id);
if (posting.Image == null)
{
posting.Image = new byte[0];
db.Entry(posting).State = EntityState.Modified;
db.SaveChanges();
}
//convert ENTITY MODEL CLASS TO Model
VideoPostingModel toRet = new VideoPostingModel();
toRet.linkIfVideo = posting.LinkIfVideo;
toRet.PostDate = posting.PostDate;
toRet.Titile = posting.Titile;
toRet.TypeOfPosting = posting.TypeOfPosting;
return View(toRet);
}
}
Model:
public class VideoPostingModel
{
..Variables
public VideoPostingModel()
{
...
}
}
View:
#model ...Models.VideoPostingModel
#{
ViewBag.Title = "Details";
}
<fieldset>
<legend>Posting</legend>
<div class="display-label">
Description</div>
<div class="display-field">
#Html.DisplayFor(model => model.Description)
</div>
<div class="display-label">
Title</div>
<div class="display-field">
#Html.DisplayFor(model => model.Titile)
</div>
<div class="display-label">
Post Date</div>
<div class="display-field">
#Html.DisplayFor(model => model.PostDate)
</div>
<div class="display-label">
Type Of Posting</div>
<div class="display-field">
#Html.DisplayFor(model => model.TypeOfPosting)
</div>
</fieldset>
<div id="youtubePlayerdiv"">
<p style="text-align: justify">
Video!</p>
<iframe id="youtubePlayer" class="youtube-player" type="text/html"
width="640" height="385" src="http://www.youtube.com/embed/<%=Model.LinkIfVideo%>" frameborder="0">
</iframe>
</div>
<!-- end youtubeplayerDiv div -->
I very much appreciate the help in advance, issue occurs right when the website hits the details method of the controller.

The error you are getting implies that somewhere on your view or _Layout you have tried to render another partial like this:
#Html.Partial("~/Views/Account/Register.cshtml")
But this partial requires a different model - RegisterModel. So one possibility is to pass a new instance of this model to the partial when rendering it:
#Html.Partial("~/Views/Account/Register.cshtml", new RegisterModel())

Related

ASP Core Ajax Posting From Partials

I have a requirement to separate parts of one page into Partial Views and one of those parts contains a form to submit data. I've been playing around with this and have managed to get the form to submit without reloading the page.
However I have two problems:
The form fields don't clear after a successful post
If validation is broken, those validation messages don't appear when returning the result.
I'll admit i'm not too familiar with AJAX in ASP to begin with but hopefully someone can hope. Here's my code:
Model
using System.ComponentModel.DataAnnotations;
namespace MVCValidation.Models
{
public class Thing
{
public int Id { get; set; }
[Required]
public string Value { get; set; }
public string OtherValue { get; set; }
}
}
Main View (_Index.cshtml)
#model MVCValidation.Models.Thing
#{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Ajax Partial Test</h1>
</div>
<div class="row">
<div class="col">
<form asp-controller="Home" asp-action="Edit" data-ajax="true" data-ajax-method="POST">
#await Html.PartialAsync("_Form", Model)
</form>
</div>
</div>
Partial View (_Form.cshtml)
#model MVCValidation.Models.Thing
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new {#class = "text-danger"})
#Html.HiddenFor(m => m.Id)
<div class="form-group">
#Html.LabelFor(m => m.Value, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(m => m.Value, new {htmlAttributes = new { #class = "form-control" }})
#Html.ValidationMessageFor(m => m.Value, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="submit" class="btn btn-success"/>
</div>
</div>
</div>
Controller (HomeController)
namespace MVCValidation.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public Thing GetThing()
{
return new Thing(){Id = 1, OtherValue = "Other"};
}
public IActionResult Index()
{
return View(GetThing());
}
[ValidateAntiForgeryToken]
[HttpPost]
public IActionResult Edit(Thing thing)
{
if(ModelState.IsValid)
{
ModelState.Clear();
return PartialView("_Form", GetThing());
}
return PartialView("_Form", thing);
}
}
}
In my _Layout view I have the jquery.unobtrusive-ajax.min.js referenced and it's loading fine. Please can anyone suggest where I'm going wrong?
So, I eventually found this article: https://damienbod.com/2018/11/09/asp-net-core-mvc-ajax-form-requests-using-jquery-unobtrusive/ and saw what I was doing wrong.
I expanded my tag to look like below:
<form asp-controller="Home" asp-action="Edit"
data-ajax="true"
data-ajax-method="POST"
data-ajax-mode="replace"
data-ajax-update="#result">
<div id="result">
#await Html.PartialAsync("_Form", Model)
</div>
</form>
the PartialAsync call now takes place inside a div that ultimately will be the target for the result to populate... so it effectively replaces itself.
I also had to change the controller method to this:
[ValidateAntiForgeryToken]
[HttpPost]
public IActionResult Edit(Thing thing)
{
if(ModelState.IsValid)
{
return RedirectToAction(nameof(Index));
}
return PartialView("_Form", thing);
}
This correctly returns the partial view when the model is invalid, and allows the page to be used again if it is valid.

MVC3 custom server-side data annotation validation not working in partial view

I am trying to add custom data validation via data annotations. I am only concerned about server-side validation at this point. Everything I have seen here and elsewhere references client-side validation. I've stripped down all my code, ran a few test cases and I can get this working just fine on a regular view but as soon as the form is in a partial view, the code no longer breaks in the method to override IsValid.
In either case I can see the custom attribute being initialized. When the form is in a regular view I can see the override method being executed upon submitting the form, but when in a partial view the code never gets executed and it goes right to the HttpPost action.
I have spent the better parts of two days trying to figure this out and am at a loss. Any help would be GREATLY appreciated.
Note:
The code below does return the same view when it enters the HttpPost action. I have it like this for testing purposes. I know my override is never getting called from the partial view and thus IsValid is always true.
View showing form where the validation works
#model eRecruitBoard.ViewModels.HomeIndexViewModel
#{
ViewBag.Title = "eRecruitBoard";
}
#*<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>*#
<h2>Login/homepage</h2>
<br /><br />
<div class="errorMessage">
#Html.DisplayFor(m => m.LoginErrorMsg)
</div>
<br />
#using (Html.BeginForm("Index", "Home")) {
<div id="loginControlBox">
<fieldset>
<legend>Welcome to eRecruitBoard</legend>
<div class="editor-label">
#Html.LabelFor(m => m.UserName)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.UserName)
#Html.ValidationMessageFor(m => m.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(m => m.Password)
</div>
<div class="editor-field">
#Html.PasswordFor(m => m.Password)
#Html.ValidationMessageFor(m => m.Password)
</div>
<div class="editor-label">
#Html.CheckBoxFor(m => m.RememberMe)
#Html.LabelFor(m => m.RememberMe)
</div>
<div class="editor-label">
#Html.EditorFor(m => m.Date)
#Html.ValidationMessageFor(m => m.Date)
</div>
<p>
<input type="submit" value="Log In" />
</p>
</fieldset>
</div>
}
<div>
#Html.Action("BlankForm", "TestForm")
</div>
Partial View (these script calls also come in via _Layout, but I had them here for testing as well)
#model eRecruitBoard.ViewModels.TestFormViewModel
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/MicrosoftAjax.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/MicrosoftMvcAjax.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/MicrosoftMvcValidation.js")" type="text/javascript"></script>
#using (Html.BeginForm("NewActivity2", "TestForm", FormMethod.Post))
{
<fieldset>
<legend>Test Form</legend>
<br />
#Html.LabelFor(m => m.Date)
#Html.EditorFor(m => m.Date)
#Html.ValidationMessageFor(m => m.Date)
<input id="activityTimelineSubmit" type="submit" value="Submit" />
</fieldset>
}
ViewModel (for partial view)
namespace eRecruitBoard.ViewModels
{
public class TestFormViewModel
{
[Required]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MM/dd/yyyy}")]
[NonFutureDate()]
[Display(Name = "Date")]
public DateTime Date { get; set; }
}
}
Controller (for partial view)
namespace eRecruitBoard.Controllers
{
public class TestFormController :BaseController
{
public ActionResult BlankForm()
{
var viewModel = new TestFormViewModel
{
Date = DateTime.Today
};
return PartialView("_TestForm", viewModel);
}
[HttpPost]
public ActionResult NewActivity2(DateTime Date)
{
if (!ModelState.IsValid)
return RedirectToAction("Index", "Home");
else
return RedirectToAction("Index", "Home");
}
}
}
Validation code
using System;
using System.ComponentModel.DataAnnotations;
namespace eRecruitBoard.WebLibrary.Validation
{
[AttributeUsageAttribute(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
public class NonFutureDateAttribute : ValidationAttribute //public sealed class
{
public NonFutureDateAttribute(): base("Activity can only be saved for today or dates in the past.")
{
}
public override bool IsValid(object value)
{
DateTime dateToCheck = (DateTime)value;
return (dateToCheck <= DateTime.Today);
}
}
}
If you RedirectToAction you lose all validation. You have to return PartialView(model) in your POST action. That would require changing the parameter type of NewActivity2 to TestFormViewModel instead of DateTime.
Update your code with example of how you display the partial view (#Html.Partial() or javascript) if it still doesnt work.

DataAnnotations on Entity not displaying in View

I have a Supplier Entitiy that contains
ID - int
Status - string
Name - string
CreateDate- datetime
I am using the partial class method to create Data Annotations for the above Entity.as described here
namespace TemplateEx.Models
{
[MetadataType(typeof(SupplierMetadata))]
public partial class Supplier
{
// Note this class has nothing in it. It's just here to add the class-level attribute.
}
public class SupplierMetadata
{
// Name the field the same as EF named the property - "FirstName" for example.
// Also, the type needs to match. Basically just redeclare it.
// Note that this is a field. I think it can be a property too, but fields definitely should work.
[Required]
[Display(Name = "Supplier Name")]
public string Name;
}
}
My defined a controller action as below
public ViewResult Details(int id)
{
Supplier supplier = db.Suppliers1.Single(s => s.ID == id);
return View(supplier);
}
When I create a view for this action and picked the Details scaffolding for the Supplier entity following is what I got as a view
#model TemplateEx.Models.Supplier
#{
ViewBag.Title = "Details";
}
<h2>Details</h2>
<fieldset>
<legend>Supplier</legend>
<div class="display-label">CreateDate</div>
<div class="display-field">
#Html.DisplayFor(model => model.CreateDate)
</div>
<div class="display-label">Status</div>
<div class="display-field">
#Html.DisplayFor(model => model.Status)
</div>
<div class="display-label">Name</div>
<div class="display-field">
#Html.DisplayFor(model => model.Name)
</div>
</fieldset>
<p>
#Html.ActionLink("Edit", "Edit", new { id=Model.ID }) |
#Html.ActionLink("Back to List", "Index")
</p>
Notice how the model.Name has a "Name" label instead of "Supplier Name".What am I doing wrong?
replace
<div class="display-label">Name</div>
with
<div class="display-label">#Html.LabelFor(model => model.Name)</div>
Edit :
For the second question, look here
How can i enforce the scaffolding automatically generated code to display the Label and the EditorFor text field at the same line in my asp.net mvc 3 (specially last answer)

Can't add file upload capability to generated MVC3 page

I'm new to MCV and I'm learning MVC3. I created a model and a controller and view was generated for me. The generated code makes perfect sense to me. I wanted to modify the generated view and controller so that I could upload a file when I "create" a new record. There is a lot of good information out there about how to do this. Specifically I tried this: http://haacked.com/archive/2010/07/16/uploading-files-with-aspnetmvc.aspx
The problem is that even when I select a file (not large) and submit, there are no files in the request. That is, Request.Files.Count is 0.
If I create the controller and and view from scratch, in the same project (no model), the example works just fine. I just can't add that functionality to the generated page. Basically, I'm trying get the Create action to also send the file. For example, create a new product entry and send the picture with it.
Example Create view:
#model Product.Models.Find
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm("Create", "Find", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Find</legend>
<input type="file" id="file" />
<div class="editor-label">
#Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Title)
#Html.ValidationMessageFor(model => model.Title)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Description)
#Html.ValidationMessageFor(model => model.Description)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Example Controller:
[HttpPost]
public ActionResult Create(Product product)
{
if (ModelState.IsValid)
{
if (Request.Files.Count > 0 && Request.Files[0] != null)
{
//Not getting here
}
db.Products.Add(product);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(find);
}
This will create the record just fine but there are not files associated with the Request.
I've also tried a controller action like this:
[HttpPost]
public ActionResult Create(HttpPostedFileBase file)
{
if (file.ContentLength > 0)
{
//Not getting here
}
return RedirectToAction("Index");
}
I'm wondering if maybe you can't post a file at the same time as posting form fields? If that is the case, what are some patterns for creating a new record and associating a picture (or other file) with it?
Thanks
Create a ViewModel which has properties to handle your image and Product deatils
public class ProductViewModel
{
public string ImageURL { set;get;}
public string Title { set;get;}
public string Description { set;get;}
}
And in your HTTPGET Action method, return this ViewModel object to your strongly typed view
public ActionResult Create()
{
ProductViewModel objVM = new ProductViewModel();
return View(objVM);
}
And in your View
#model ProductViewModel
<h2>Add Product</h2>
#using (Html.BeginForm("Create", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.TextBoxFor(m => m.Title) <br/>
#Html.TextBoxFor(m => m.Description ) <br/>
<input type="file" name="file" />
<input type="submit" value="Upload" />
#Html.HiddenFor(m => m.ImageURL )
}
Now in your HttpPost action method, accept this ViewModel and File
[HttpPost]
public ActionResult Create(HttpPostedFileBase file, ProductViewModel objVM)
{
if(file==null)
{
return View("Create",objVM);
}
else
{
//You can check ModeState.IsValid if you have to check any model validations and do further processing with the data here.
//Now you have everything here in your parameters, you can access those and save
}
}
You will have to create a ViewModel for Product (maybe ProductViewModel) and add a HttpPostedFileBase field with the same name as the field of the form and use that instead of the Product in the action of the controller.
A ViewModel is nothing but a model used for specific views. Most of the times, with extra data to generate the view or to decompose and form the model on the controller action.
public ProductViewModel
{
public string Cod { get; set; }
// All needed fields goes here
public HttpPostedFileBase File{ get; set; }
/// Empty constructor and so on ...
}

ASP.NET MVC3 C# - edit functionality in detail view of a different controller

I'm trying to create a forum. I'm trying to have the functionality of 'post edit' in 'thread details'
I have the standard OTB Thread index view, and when you click on 'details' it shows the OTB Thread details, I have added a foreach to display the posts relating to that thread underneath.
I'm now struggling with adding/allowing the posts that are displayed underneath to be edited. Specifically show/hide.
In context, all posts are 'hidden' until an administrator clicks a button to 'show' a post, and vice versa
Thread Controller:
public ViewResult Details(int id)
{
tb_SH_Forum_Threads tb_sh_forum_threads = db.tb_SH_Forum_Threads.Single(t => t.Thread_ID == id);
ViewBag.Private_ID = new SelectList(db.tb_SH_Forum_PrivateDesc, "Private_ID", "Private_Desc");
return View(tb_sh_forum_threads);
}
View:
#model Shareholder_Forum.Models.tb_SH_Forum_Threads
#{
ViewBag.Title = "Details";
}
<h2>Details</h2>
<fieldset>
<legend>tb_SH_Forum_Threads</legend>
<div class="display-label">Thread_Title</div>
<div class="display-field">
#Html.DisplayFor(model => model.Thread_Title)
</div>
<div class="display-label">Thread_Details</div>
<div class="display-field">
#Html.DisplayFor(model => model.Thread_Details)
</div>
<div class="display-label">tb_SH_Forum_Categories</div>
<div class="display-field">
#Html.DisplayFor(model => model.tb_SH_Forum_Categories.Category_Description)
</div>
<div class="display-label">Thread_Date</div>
<div class="display-field">
#Html.DisplayFor(model => model.Thread_Date)
</div>
<div class="display-label">Replies</div>
<div class="display-field">
#Html.DisplayFor(model => model.Replies)
</div>
</fieldset>
#foreach
(var post in Model.tb_SH_Forum_Posts.Where(w => w.Private_ID == 1).OrderBy(o => o.Post_Date))
{
<div class ="post">
<fieldset>
<p class="post_details">At #post.Post_Date By #(post.Anon == true ? "Anonymous" : post.Username)
</p>
#post.Post_Desc
</fieldset>
</div>}
<p>
#Html.ActionLink("Back to List", "Index")|
</p>
I think I need to use RenderAction and/or Partial views, but I don't understand. Any advice, or point me in the right direction where I can learn about this.
As always, very much appreciated.
Not certain I understand what you want, but here's how you could do what I think you're asking.
#foreach (var post in Model.tb_SH_Forum_Posts.Where(w => w.Private_ID == 1).OrderBy(o => o.Post_Date))
{
if(post.IsEditable) //however you're determining if they can edit the post. Alternatively display both this and the else and use javascript to toggle which one you show
{
///...Your old view post code
}
else
{
#Html.RenderPartial("EditPost", new {postdata = post})
}
}
Make a model
public class PostDataViewModel
{
public Post PostData
{
get;
set;
}
}
EditPost.cshtml
#model PostDataViewModel
// The editable form and button to submit to SaveForumPost action
Save it with
public virtual ActionResult SaveForumPost(PostaDavaViewModel model)
{
//... save edits
// either return a redirect to Detail, or if you don't want to refresh the page call this with ajax
}

Resources