Required Meta Data Validation is not working on Partial Views - asp.net

I have the following Main view inside my asp.net mvc-4:-
#model TMS.ViewModels.SwitchJoin
#Ajax.ActionLink("Add Port Info", "CreatePort","Switch",
new { switchid = Model.Switch.SwitchID },
new AjaxOptions {
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "AssignPort" ,
LoadingElementId = "progress"
}
)
</p>
//code goes here
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
And the following two partial view;-
#model TMS.Models.TMSSwitchPort
#using (Ajax.BeginForm("CreatePort", "Switch", new AjaxOptions
{
InsertionMode = InsertionMode.InsertAfter,
UpdateTargetId = "Porttable",
LoadingElementId = "loadingimag",
HttpMethod= "POST",
OnSuccess="submitform"
}))
{
#Html.ValidationSummary(true)
#Html.HiddenFor(model=>model.SwitchID)
#Html.Partial("_CreateOrEditPort", Model)
<input type="submit" value="Save" class="btn btn-primary"/>
}
&&&
#model TMS.Models.TMSSwitchPort
#Html.AntiForgeryToken()
<div>
<span class="f">Device Tag</span>
#Html.TextBoxFor(model => model.Technology.Tag)
#Html.ValidationMessageFor(model => model.Technology.Tag)
<span class="f"> Port Number</span>
#Html.TextBoxFor(model => model.PortNumber)
#Html.ValidationMessageFor(model => model.PortNumber)
</div>
And I have the following Meta type Model class:-
public class TMSSwitchPort_Validation
{
[Required]
public string PortNumber { get; set; }
}
}
But on the __CreateOrEditPort partial view the required validation will not fire? Can anyone advice please?

Answer #develiper10214 is right but you also write about MetaType model class. I quess, are you want MetadataType class for your class.
If yes. You need to watch a few rules.
Your class and Metadata class need to in the same namespace (if you use this for metadata in EF database first and partial model class).
You need to "tell" your class than you use a metadata class.
Fields in class and metadata class need to be the same.
Example:
namespace TMS.Models
{
public partial class TMSSwitchPort
{
public string PortNumber { get; set; }
}
}
Another class:
namespace TMS.Models
{
[MetadataType(typeof(TMSSwitchPortMetadata))]
public partial class TMSSwitchPort
{
//Nothing
}
public class TMSSwitchPortMetadata
{
[Required]
public string PortNumber { get; set; }
}
}

Related

empty return variable in controller - asp.net

Although home.dilstring data is displayed in html, when I check the data with console.write, it shows an empty value. view in html.
Why does it appear empty inside the controller of your class when loading?
Controller:
public class HomeController : BaseController
{
[HttpGet]
public ActionResult Index()
{
Home home = new Home();
using (var db2 = new DBservice...())
{
Console.Write("deneme", home.dilstring);
}
}
}
Model class:
public class Home
{
[Display(Name = "language", ResourceType = typeof(Localization))]
public string dilstring { get; set; }
}
View:
#model ...Models.Home
<p class="vc_subtitle">
#Html.LabelFor(model => model.dilstring)
</p>
home object is newly instantiated object from Home class so "dilstring" property value will be empty if not assigned with default value
LabelFor will just create label element for the specified property and show it's name
so #Html.LabelFor(model => model.dilstring) will generate html below
<label for="dilstring">dilstring</label>
if you change "LabelFor" with "DisplayFor" you will get empty value as controller
to Understand the difference try below
public class HomeController : BaseController
{
[HttpGet]
public ActionResult Index()
{
Home home = new Home();
using (var db2 = new DBservice...())
{
Console.Write("deneme", home.dilstring);
home.dilstring = "Hi";
Console.Write("deneme", home.dilstring);
}
}
return View(home);
}
And for view
#model ...Models.Home
<p class="vc_subtitle">
#Html.LabelFor(model => model.dilstring)
</p>
<p class="vc_subtitle">
#Html.DisplayFor(model => model.dilstring)
</p>

editor template return null value

I have created an editor template base on this article ASP.NET MVC: Annotated for Input by Dino Esposito
Everything works fine until i press the submit button. I find out that my POST function return model is NULL, its like the model is not bind to the view. I have been trying all trick that I know and I found from the internet but I still can't fix it.
This is my controller
// GET: /Asset/New
public ActionResult New()
{
ViewBag.typeID = new SelectList(db.Ref_Asset_Types, "ID", "name");
return View(new AssetViewModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult New(AssetViewModel vm)
// vm.asset should contain new value but currently return null
{
if (ModelState.IsValid)
{
db.Assets.Add(vm.asset);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.typeID = new SelectList(db.Ref_Asset_Types, "ID", "name", vm.asset.typeID);
return View("New", vm);
}
this is my view
#using (Html.BeginForm("New","Asset","POST")) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.EditorFor(m=>m.asset, "InputTemplate" )
// note : the code works if i don't use my own template ==> #Html.EditorFor(m=>m.asset)
<div class="form-actions btn pull-right">
#Html.ActionLink("Back to List", "Index", null, new { #class = "btn btn-sm"})
<button type="reset" class="btn btn-sm" value="Index">
Reset
</button>
<button type="submit" class="btn btn-sm btn-success">
<i class="glyphicon glyphicon-plus"></i>
Tambah
</button>
</div>
}
and this is my InputTemplate
#inherits System.Web.Mvc.WebViewPage
#if (Model == null)
{
<span>#ViewData.ModelMetadata.NullDisplayText</span>
}
else
{
foreach (var prop in ViewData
.ModelMetadata
.Properties
.Where(pm => pm.ShowForDisplay && !ViewData.TemplateInfo.Visited(pm)))
{
if (prop.DisplayName != null) { // only display prop not of ComplexType
// note : using bootstrap for css styling
<div class="form-group col-xs-6">
<label class="col-xs-4 control-label text-right">
<span style="color:red"> #(prop.IsRequired ? "*" : "") </span>
<span>#prop.GetDisplayName()</span>
</label>
<div class="col-xs-8">
#if(prop.IsReadOnly)
{
<span class="readonly-field">#Html.Display(prop.PropertyName)</span>
}
else if (prop.TemplateHint == "DropDown")
{
<span>#Html.DropDownList(prop.PropertyName,(IEnumerable<SelectListItem>) ViewData[prop.PropertyName], new { #class = "form-control" })</span>
<span>#Html.ValidationMessage(prop.PropertyName)</span>
}
else
{
<div class="editor-field">
<span>#Html.Editor(prop.PropertyName, new { #class = "text-box single-line form-control" })</span>
<span>#Html.ValidationMessage(prop.PropertyName, new { #class = "label-danger" } )</span>
</div>
}
</div>
</div>
} // if
} // foreach
}
This is my viewmodel
using System;
using SIGMA.Models;
namespace SIGMA.ViewModels
{
public class AssetViewModel
{
public AssetViewModel()
{
asset = new Asset();
}
public Asset asset { get; set; }
}
}
This is my model
public class Asset
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
[HiddenInput(DisplayValue = false)]
public int ID { get; set; }
[DisplayName("No. Siri")]
[StringLength(45)]
public string serial_num { get; set; }
[DisplayName("Model")]
[Required(ErrorMessage = "Model perlu diisi!")]
[StringLength(45)]
public string model { get; set; }
[DisplayName("Harga Seunit")]
[RegularExpression(#"^\d{0,6}(\.\d{2})?$", ErrorMessage = "Sila gunakan format harga yang betul.")]
public float? unit_cost { get; set; }
[UIHint("DropDown")]
[DisplayName("Jenis Aset")]
[Required(ErrorMessage = "Jenis aset perlu dipilih!")]
[DisplayFormat(NullDisplayText = "Belum didaftar")]
public int? typeID { get; set; }
public virtual Ref_Asset_Type type { get; set; }
}
Sorry guys for the trouble.. i think i solve it.
My biggest mistake is using reserved word 'model' and 'type' as my property name. This some how cause problem to asp.net in interpreting my model using the user define editor template.
Once I change my property name - model to model_name and type to asset_type, i can see the my entry in my return model already.
Thanks to all
.... spends the whole day and night for this silly mistake but the lesson learn is worth it

[Bind(Include = does not work with collection

I have a controller that looks like below:
public async Task<ActionResult> CreateProduct([Bind(Include = "Id,MyCollection")] MyClass myClass)
and this is the view:
<div class="form-group">
#Html.LabelFor(model => model.Id, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Id)
#Html.ValidationMessageFor(model => model.Id)
</div>
</div>
<table>
<tr>
<th>#Html.LabelFor(model => model.MyCollection.First().A)</th>
<th>#Html.LabelFor(model => model.MyCollection.First().B)</th>
<th>#Html.LabelFor(model => model.MyCollection.First().C)</th>
</tr>
#foreach (var item in this.Model.Warnings)
{
<tr>
<td>#Html.ValueFor(model => item.A)</td>
<td>#Html.EditorFor(model => item.B)</td>
<td>#Html.EditorFor(model => item.C)</td>
</tr>
}
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
when I click Save, it posts to the action but only Id is assigned to the object, not myCollection.
What do I need to do to include the collection when posting them to controller?
Update
Model is generated by Entity Framework
public abstract partial class MyBaseClass
{
public Module()
{
this.MyCollection= new HashSet<Warning>();
}
public int Id { get; set; }
public virtual ICollection<Warning> MyCollection { get; set; }
}
public partial class MyClass : MyBaseClass
{
// more properties that aren't used on this controller
}
In order to get this to work you need to understand how ASP.NET MVC handles model binding for a List. Scott Hansleman has a good post explaining this.
Since your question was rather vague in terms of what the actual properties you're dealing with are, I put together a little example which successfully binds to a list:
Controller
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
//Initial test data
var zoo = new Zoo()
{
Id = 1,
Name = "Vilas Zoo",
Animals = new List<Animal>()
{
new Animal() {
Id = 1,
Name = "Red Panda"
},
new Animal() {
Id = 2,
Name = "Sloth"
},
new Animal() {
Id = 3,
Name = "Badger"
},
}
};
return View(zoo);
}
[HttpPost]
public JsonResult Index(Zoo zoo)
{
return Json(zoo);
}
}
Model
public class Zoo
{
public int Id { get; set; }
public string Name { get; set; }
public List<Animal> Animals { get; set; }
}
public class Animal
{
public int Id { get; set; }
public string Name { get; set; }
}
View
<h1>#Model.Id - #Model.Name</h1>
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
for (var i=0; i < Model.Animals.Count; i++)
{
#Html.EditorFor(m => Model.Animals[i])
}
<button type="submit">Save it, yo</button>
}
Notice how I'm using a for loop instead of a foreach and the actual index of the loop is being used in the call to EditorFor.

Partial views inside my asp.net mvc will ignore all the model data annotations

I have the following action method which render the following partial view:-
public ActionResult CreateVMNetwork(int vmid)
{
AssignIps vmips = new AssignIps()
{
TechnologyIP = new TechnologyIP() { TechnologyID = vmid},
IsTMSIPUnique = true,
IsTMSMACUnique = true
};
return PartialView("_CreateNetworkInfo",vmips);
}
The partial view is :-
model TMS.ViewModels.AssignIps
#if (this.ViewContext.FormContext == null)
{
this.ViewContext.FormContext = new FormContext();
}
#using (Ajax.BeginForm("CreateVMNetwork", "VirtualMachine", new AjaxOptions
{
InsertionMode = InsertionMode.InsertAfter,
UpdateTargetId = "networktable",
LoadingElementId = "loadingimag",
HttpMethod= "POST",
OnSuccess="submitform"
}))
{
#Html.ValidationSummary(true)
#Html.HiddenFor(model=>model.TechnologyIP.TechnologyID)
#Html.AntiForgeryToken()
<div>
<span class="f">IP Address</span>
#Html.EditorFor(model => model.TechnologyIP.IPAddress)
#Html.ValidationMessageFor(model => model.TechnologyIP.IPAddress)
<input type="CheckBox" name="IsTMSIPUnique" value="true" #(Html.Raw(Model.IsTMSMACUnique ? "checked=\"checked\"" : "")) /> IP Unique. |
<span class="f"> MAC Address</span>
#Html.EditorFor(model => model.TechnologyIP.MACAddress)
#Html.ValidationMessageFor(model => model.TechnologyIP.MACAddress)
<input type="CheckBox" name="IsTMSMACUnique" value="true" #(Html.Raw(Model.IsTMSMACUnique ? "checked=\"checked\"" : "")) /> MAC Unique.
</div>
<input type="submit" value="Save" class="btn btn-primary"/>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
but all the data annotation on the view model will not fire on the partial view , the AssignIps view model class is :-
namespace TMS.ViewModels
{
public class AssignIps
{
public TechnologyIP TechnologyIP { get; set; }
public bool IsTMSIPUnique { get; set; }
public bool IsTMSMACUnique { get; set; }
}
}
and he TechnologyIP model class is :-
namespace TMS.Models
{
[MetadataType(typeof(TechnologyIP_Validation))]
public partial class TechnologyIP
{}}
namespace TMS.Models
{
public class TechnologyIP_Validation
{
[Required]
public string IPAddress { get; set; }
but the [Required] data annotation on the TechnologyIP model, will not fire on the partial view,, can anyone adovce please?
Thanks.
Sections defined in your layout view don't get populated when using PartialViewResult, so the unobtrusive validation scripts are not being added.
You can test this by creating an action on your controller that just returns a partial view, and then call this via $.get() (using jQuery, obviously). If you use console.log(), you can inspect the result in Firebug. You could also use something like Fiddler; regardless, if you look at the HTML returned you will not see the script references anywhere.
Exactly, a wrong practice is to have:
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
in the partial view, try to do it just putting
#Scripts.Render("~/bundles/jqueryval")
and it should work!

LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression

This is my controller class
public class HomeController : Controller
{
private rikuEntities rk = new rikuEntities();
public ActionResult Index()
{
var db = new rikuEntities();
IEnumerable<SelectListItem> items = db.emp.Select(c => new
SelectListItem
{
Value = c.Id.ToString(),
Text = c.name
});
ViewBag.CategoryID = items;
return View();
}
}
this is my view
#using (Html.BeginForm("viewToController", "Home"))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>emp</legend>
<div class="editor-field">
#Html.DropDownList("CategoryID", (IEnumerable<SelectListItem>) ViewBag.Categories)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
whenever I run this program I get this error:
LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression." in the statement #Html.DropDownList("CategoryID", (IEnumerable) ViewBag.Categories). i am using entity framework mechanism for databse connection. please help me to find out the error...
I would recommend you to use view models and strongly typed views instead of ViewBag. So start with defining your view model:
public class EmployeeViewModel
{
public string CategoryId { get; set; }
public IEnumerable<Employee> Categories { get; set; }
}
then in the controller populate this view model:
public class HomeController : Controller
{
public ActionResult Index()
{
var db = new rikuEntities();
var model = new EmployeeViewModel
{
Categories = db.emp.ToArray() // <-- you probably want categories here
};
return View(model);
}
}
and in the view:
#model EmployeeViewModel
#using (Html.BeginForm("viewToController", "Home"))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>emp</legend>
<div class="editor-field">
#Html.DropDownListFor(
x => x.CategoryId,
new SelectList(Model.Categories, "Id", "name")
)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Sadly EF does not know how to convert ToString() to an SQL statement.
You must, therefore, use the embedded function SqlFunctions.StringConvert.
There is no overload for int so you will need to typecast to double :-(
var items = from v in db.emp
select new SelectListItem
{
Text = c.name,
Code = SqlFunctions.StringConvert((double)c.Id)
};

Resources