ASP.NET MVC3: TryUpdateModel throwing an exception - exception

I have a view which accepts the following model:
Inherits="System.Web.Mvc.ViewPage<MVC_WordsByME.Models.JobCreationModel>"
This posts back to the following action:
[HttpPost]
public ActionResult Create(FormCollection formValues)
{
var job = new JobCreationModel();
if (TryUpdateModel(job))
{
_jobRepository.AddJob(job);
_jobRepository.Save();
return RedirectToAction("Index");
}
return View(job);
}
However, on posting back the following exception is thrown:
Unable to cast object of type 'System.Int32' to type 'System.String'.
Description: An unhandled exception occurred during the execution of the current web request.
Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidCastException: Unable to cast object of type 'System.Int32' to type 'System.String'.
Source Error:
Line 135: {
Line 136: var job = new JobCreationModel();
Line 137: if (TryUpdateModel(job))
Line 138: {
Line 139: _jobRepository.AddJob((Job)job);
Although I can't highlight it here, it's line 137 that the exception occurs on. I can't step into this method, so how can I determine what's causing this exception?
Also, isn't TryUpdateModel supposed to shelter me from any exceptions, simply returning true or false to reflect the result? I wasn't aware that it could throw an exception.
UPDATE: here's the model (both derived and base):
public class JobCreationModel : Job
{
//
// Properties
public SelectList ClientsList { get; private set; }
public SelectList Languages { get; set; }
public SelectList Users { get; set; }
//
// Constructors
public JobCreationModel()
{
var userCurrent = Membership.GetUser();
SentDate = DateTime.Now;
WorkedBy = userCurrent != null ? userCurrent.UserName : string.Empty;
DeadlineDate = DateTime.Now;
ReceivedDate = DateTime.Now;
var clientRepository = new ClientRepository();
ClientsList = new SelectList(clientRepository.GetAllClients(), "ID", "OrganisationName");
var languageRepository = new LanguageRepository();
Languages = new SelectList(languageRepository.GetAllLanguages(), "ID", "Code");
var userList = Membership.GetAllUsers();
Users = new SelectList(userList.Cast<MembershipUser>().ToList(), "UserName", "UserName", userCurrent);
}
public JobCreationModel(Job job)
{
var userCurrent = Membership.GetUser();
Client = job.Client;
ClientName = job.ClientName;
DeadlineDate = job.DeadlineDate;
FixedCost = job.FixedCost;
ID = job.ID;
Invoice = job.Invoice;
JobDescription = job.JobDescription;
JobFileName = job.JobFileName;
LanguageFrom = job.LanguageFrom;
LanguageTo = job.LanguageTo;
PONumber = job.PONumber;
ReceivedDate = job.ReceivedDate;
SentDate = job.SentDate;
WordCost = job.WordCost;
WordCount = job.WordCount;
WorkedBy = job.WorkedBy;
var clientRepository = new ClientRepository();
ClientsList = new SelectList(clientRepository.GetAllClients(), "ID", "OrganisationName");
var languageRepository = new LanguageRepository();
Languages = new SelectList(languageRepository.GetAllLanguages(), "ID", "Code");
var userList = Membership.GetAllUsers();
Users = new SelectList(userList.Cast<MembershipUser>().ToList(), "UserName", "UserName", userCurrent);
}
}
The base type is an entity, and the best way I could think of to show it is to display the XML behind it:
<EntityType Name="Jobs">
<Key>
<PropertyRef Name="ID" />
</Key>
<Property Name="ID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
<Property Name="JobDescription" Type="nvarchar" Nullable="false" MaxLength="200" />
<Property Name="ReceivedDate" Type="datetime" Nullable="false" />
<Property Name="DeadlineDate" Type="datetime" Nullable="false" />
<Property Name="SentDate" Type="datetime" Nullable="false" />
<Property Name="Invoice" Type="int" />
<Property Name="WordCount" Type="int" Nullable="false" />
<Property Name="WordCost" Type="float" Nullable="false" />
<Property Name="FixedCost" Type="float" Nullable="false" />
<Property Name="Client" Type="int" Nullable="false" />
<Property Name="JobFileName" Type="nvarchar" Nullable="false" MaxLength="500" />
<Property Name="WorkedBy" Type="varchar" Nullable="false" MaxLength="50" />
<Property Name="PONumber" Type="varchar" Nullable="false" MaxLength="50" />
<Property Name="LanguageFrom" Type="int" Nullable="false" />
<Property Name="LanguageTo" Type="int" Nullable="false" />
</EntityType>
This then has a buddy class to extend it:
[MetadataType(typeof(JobValidation))]
[Bind(Include = "Client,SentDate,JobFileName,JobDescription,WordCost,WordCount,WorkedBy")]
public partial class Job
{
public IEnumerable Clients
{
get
{
var clientRepository = new ClientRepository();
return clientRepository.GetAllClients();
}
}
public string ClientName { get; set; }
public string SelectedMonth { get; set; }
public string SelectedYear { get; set; }
}
public class JobValidation
{
[Required(ErrorMessage = "Please select a client for the sent job")]
[Range(1, 999999, ErrorMessage = "Please select a client")]
public int Client { get; set; }
[Required(ErrorMessage = "Please enter the completion date for this job")]
[DataType(DataType.Date, ErrorMessage = "The date entered is not in a recognised format")]
public DateTime SentDate { get; set; }
[Required(ErrorMessage = "Job file must have a name")]
[StringLength(500, ErrorMessage = "Job file name must not be longer than 500 characters")]
public string JobFileName { get; set; }
[Required(ErrorMessage = "Job must have a name")]
[StringLength(200, ErrorMessage = "Job name must not be longer than 200 characters")]
public string JobDescription { get; set; }
[Required(ErrorMessage = "Please enter the word cost for the sent job")]
[StringLength(6, ErrorMessage = "The word cost should not exceed 5 digits")]
[DataType(DataType.Currency, ErrorMessage = "The word cost was not recognised as an amount of currency")]
public string WordCost { get; set; }
[Required(ErrorMessage = "Please enter the word count for the sent job")]
[StringLength(8, ErrorMessage = "The word count must not exceed 99999999")]
public string WordCount { get; set; }
public string WorkedBy { get; set; }
}
Finally, here's the relevant part of the view:
<% using (Html.BeginForm()) {%>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Job Details</legend>
<div class="editor-label">
Job description
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.JobDescription)%>
<%: Html.ValidationMessageFor(model => model.JobDescription)%>
</div>
<div class="editor-label">
PO number
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.PONumber)%>
<%: Html.ValidationMessageFor(model => model.PONumber)%>
</div>
<div class="editor-label">
Date received
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.ReceivedDate)%>
<%: Html.ValidationMessageFor(model => model.ReceivedDate)%>
</div>
<div class="editor-label">
Deadline Date
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.DeadlineDate)%>
<%: Html.ValidationMessageFor(model => model.DeadlineDate)%>
</div>
<div class="editor-label">
Date sent
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.SentDate)%>
<%: Html.ValidationMessageFor(model => model.SentDate)%>
</div>
<div class="editor-label">
Is fixed-cost? <input type="checkbox" id="fixed-cost" />
</div>
<div id="word-priced-job">
<div class="editor-label">
Word count
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.WordCount)%>
<%: Html.ValidationMessageFor(model => model.WordCount)%>
</div>
<div class="editor-label">
Word cost
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.WordCost)%>
<%: Html.ValidationMessageFor(model => model.WordCost)%>
</div>
</div>
<div id="fixed-price-job" class="faded">
<div class="editor-label">
Fixed cost
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.FixedCost)%>
<%: Html.ValidationMessageFor(model => model.FixedCost)%>
</div>
</div>
<div class="editor-label">
Languages
</div>
<div class="editor-field">
<%: Html.DropDownListFor(model => model.LanguageFrom, Model.Languages, "-- Select --") %><%: Html.ValidationMessageFor(model => model.LanguageFrom)%>
<span> - to - </span>
<%: Html.DropDownListFor(model => model.LanguageTo, Model.Languages, "-- Select --") %><%: Html.ValidationMessageFor(model => model.LanguageTo)%>
</div>
<div class="editor-label">
Client
</div>
<div class="editor-field">
<%: Html.DropDownListFor(model => model.Client, Model.ClientsList, "-- Select --") %> <%: Html.ActionLink("Create a new client", "Create", "Clients") %>
<%: Html.ValidationMessageFor(model => model.Client)%>
</div>
<div class="editor-label">
Job file name
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.JobFileName) %>
<%: Html.ValidationMessageFor(model => model.JobFileName)%>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.WorkedBy)%>
</div>
<div class="editor-field">
<%: Html.DropDownListFor(model => model.WorkedBy, Model.Users) %>
</div>
<p>
<input id="btnSave" type="submit" value="Save" />
</p>
</fieldset>
<% } %>

No idea why this exception occurs without seeing your model and view code but try simplifying your action like this:
[HttpPost]
public ActionResult Create(JobCreationModel job)
{
if (!ModelState.IsValid)
{
return View(job);
}
_jobRepository.AddJob(job);
_jobRepository.Save();
return RedirectToAction("Index");
}

I've changed:
[StringLength(3)]
public int? GroupID { get; set; }
to:
public int? GroupID { get; set; }
So the StringLength attribute made problems, because GroupID was int? and as it seems StringLength attribute is valid only for strings.

Related

Unable to see data entry after it's created | The JSON value could not be converted to BandA.Shared.Domain.Applier

Currently creating a Blazor Web app using Visual Studios.
Was able to create and delete entity data through index page:
base page
The problems start when i try to run this data through and Edit and View pages. When I try to, I get this error chain:
Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: The JSON value could not be converted to BandA.Shared.Domain.Applier. Path: $ | LineNumber: 0 | BytePositionInLine: 1.
System.Text.Json.JsonException: The JSON value could not be converted to BandA.Shared.Domain.Applier. Path: $ | LineNumber: 0 | BytePositionInLine: 1.
at System.Text.Json.ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Type propertyType)
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1[[BandA.Shared.Domain.Applier, BandA.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, Applier& value)
at System.Text.Json.Serialization.JsonConverter`1[[BandA.Shared.Domain.Applier, BandA.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, Applier& value)
at System.Text.Json.Serialization.JsonConverter`1[[BandA.Shared.Domain.Applier, BandA.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore[Applier](JsonConverter jsonConverter, Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore[Applier](JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& state, JsonConverter converterBase)
at System.Text.Json.JsonSerializer.<ReadAsync>d__20`1[[BandA.Shared.Domain.Applier, BandA.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
at System.Net.Http.Json.HttpContentJsonExtensions.<ReadFromJsonAsyncCore>d__3`1[[BandA.Shared.Domain.Applier, BandA.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
at System.Net.Http.Json.HttpClientJsonExtensions.<GetFromJsonAsyncCore>d__9`1[[BandA.Shared.Domain.Applier, BandA.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
at BandA.Client.Pages.Applier.Edit.OnParametersSetAsync() in C:\Users\boris\source\repos\BandA\BandA\Client\Pages\Applier\Edit.razor:line 15
at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle)
I looked up thie error code's meaning and it seems to be happening when the application is trying to deserialize a JSON response obtained from an HTTP GET request into an object of type BandA.Shared.Domain.Applier. The issue might be that the JSON data doesn't match the expected structure of the Applier class but I've run a GET request through Postman and can get back my data just fine:
I'm honestly not sure how to even go about finding this problem, all related codes aren't giving back errors in Visual Studios. Can anyone shed some light on this?
Applier/Index.razor:
#page "/appliers/"
#inject HttpClient _client
#inject IJSRuntime js
#attribute [Authorize]
<h3 class="card-title"> Job Appliers </h3>
<br />
<a href="/appliers/create" class="btn btn-secondary">
<span class="oi oi-plus"></span>
Create New Applier
</a>
<br />
<br />
#if (Appliers == null)
{
<div class="alert alert-info">Loading Appliers...</div>
}
else
{
<table class="table table-responsive">
<thead>
<tr>
<th>Name</th>
<th>NRIC</th>
<th>Date of Birth</th>
<th>Gender</th>
<th>Contact Number</th>
<th>Email</th>
<th>Address</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
#foreach (var applier in Appliers)
{
<tr>
<td>#applier.FirstName #applier.LastName</td>
<td>#applier.NRIC</td>
<td>#applier.DateOfBirth</td>
<td>#applier.Gender</td>
<td>#applier.ContactNumber</td>
<td>#applier.EmailAddress</td>
<td>#applier.Address</td>
<td>
<a href="/appliers/view/#applier.Id" class="btn btn-primary">
<span class="oi oi-book"></span>
</a>
<a href="/appliers/edit/#applier.Id" class="btn btn-warning">
<span class="oi oi-pencil"></span>
</a>
<button class="btn btn-danger" #onclick="#(()=>Delete(applier.Id))">
<span class="oi oi-delete"></span>
</button>
</td>
</tr>
}
</tbody>
</table>
}
#code {
private List<Applier> Appliers;
protected async override Task OnInitializedAsync()
{
Appliers = await _client.GetFromJsonAsync<List<Applier>>($"{Endpoints.AppliersEndpoint}");
}
async Task Delete(int applierId)
{
var applier = Appliers.First(q => q.Id == applierId);
var confirm = await js.InvokeAsync<bool>("confirm", $"Do you want to delete {applier.NRIC}?");
if (confirm)
{
await _client.DeleteAsync($"{Endpoints.AppliersEndpoint}/{applierId}");
await OnInitializedAsync();
}
}
}
Applier/view.razor:
#page "/appliers/view/{id:int}"
#inject HttpClient _client
#inject NavigationManager _navManager
<h3>View</h3>
<FormComponent applier="applier" Disabled="true" />
#code { [Parameter] public int id { get; set; }
Applier applier = new Applier();
protected async override Task OnParametersSetAsync()
{
applier = await _client.GetFromJsonAsync<Applier>($"{Endpoints.AppliersEndpoint}/{id}");
} }
Applier/Edit.razor:
#page "/appliers/edit/{id:int}"
#inject HttpClient _client
#inject NavigationManager _navManager
<h3>Edit Applier</h3>
<FormComponent ButtonText="Update" OnValidSubmit="EditApplier" applier="applier" />
#code {
[Parameter] public int id { get; set; }
Applier applier = new Applier();
protected async override Task OnParametersSetAsync()
{
applier = await _client.GetFromJsonAsync<Applier>($"{Endpoints.AppliersEndpoint}/{id}");
}
async Task EditApplier()
{
await _client.PutAsJsonAsync($"{Endpoints.AppliersEndpoint}/{id}", applier);
_navManager.NavigateTo("/appliers/");
} }
Applier/FormComponents.razor:
<EditForm Model="#applier" OnValidSubmit="#OnValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<fieldset disabled="#Disabled">
<div class="form-group">
<label>First Name: </label>
<div>
<InputText #bind-Value="#applier.FirstName" class="form-control" />
<ValidationMessage For="#(() => applier.FirstName)" />
</div>
</div>
<div class="form-group">
<label>Last Name: </label>
<div>
<InputText #bind-Value="#applier.LastName" class="form-control" />
<ValidationMessage For="#(() => applier.LastName)" />
</div>
</div>
<div class="form-group">
<label>NRIC: </label>
<div>
<InputText #bind-Value="#applier.NRIC" class="form-control" />
<ValidationMessage For="#(() => applier.NRIC)" />
</div>
</div>
<div class="form-group">
<label>Date of Birth: </label>
<div>
<InputDate #bind-Value="#applier.DateOfBirth" class="form-control" />
<ValidationMessage For="#(() => applier.DateOfBirth)" />
</div>
</div>
<div class="form-group">
<label>Gender: </label>
<div>
<InputText #bind-Value="#applier.Gender" class="form-control" />
<ValidationMessage For="#(() => applier.Gender)" />
</div>
</div>
<div class="form-group">
<label>Contact Number: </label>
<div>
<InputText #bind-Value="#applier.ContactNumber" class="form-control" />
<ValidationMessage For="#(() => applier.ContactNumber)" />
</div>
</div>
<div class="form-group">
<label>Email: </label>
<div>
<InputText #bind-Value="#applier.EmailAddress" class="form-control" />
<ValidationMessage For="#(() => applier.EmailAddress)" />
</div>
</div>
<div class="form-group">
<label>Address: </label>
<div>
<InputText #bind-Value="#applier.Address" class="form-control" />
<ValidationMessage For="#(() => applier.Address)" />
</div>
</div>
</fieldset>
#if (!Disabled)
{
<button type="submit" class="btn btn-success btn-block">
#ButtonText
</button>
}
<BackToList Target="appliers" />
</EditForm>
#code {
[Parameter] public Applier applier { get; set; }
[Parameter] public string ButtonText { get; set; } = "Save";
[Parameter] public EventCallback OnValidSubmit { get; set; }
[Parameter] public bool Disabled { get; set; } = false;
}
Client/Shared/Domain/Applier.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BandA.Shared.Domain
{
public class Applier : BaseDomainModel
{
[Required]
[StringLength(100, MinimumLength = 2, ErrorMessage = "First Name does not meet length requirements")]
public string FirstName { get; set; }
[Required]
[StringLength(100, MinimumLength = 2, ErrorMessage = "Last Name does not meet length requirements")]
public string LastName { get; set; }
[Required]
[RegularExpression(#"^[STFGstfg]\d{7}[A-Za-z]", ErrorMessage = "Driving License does not meet NRIC requirements")]
//NRIC Regular Expression: [STFGstfg] - Upper or lower case s t f or g \ d{7} - 7 digits in between [A-Za-z] - last letter is an alphabet
public string NRIC { get; set; }
[Required]
public DateTime? DateOfBirth { get; set; }
//Address is not a required property, it is intentionally not given any data annotations
public string Gender { get; set; }
[Required]
[DataType(DataType.PhoneNumber)]
[RegularExpression(#"(6|8|9)\d{7}", ErrorMessage = "Contact Number is not a valid phone number")]
//Regular mobile number Expression: (6|8|9) - start with 6 8 or 9 \ d{7} - remaining 7 digits are numbers
public string ContactNumber { get; set; }
[Required]
[DataType(DataType.EmailAddress, ErrorMessage = "Email Address is not a valid email")]
[EmailAddress]
public string EmailAddress { get; set; }
//Address is not a required property, it is intentionally not given any data annotations
public string Address { get; set; }
public virtual List<Resume> Resumes { get; set; }
public virtual List<Application> Applications { get; set; }
}
}
Client/Endpoint.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BandA.Client.Static
{
public static class Endpoints
{
private static readonly string Prefix = "api";
public static readonly string AppliersEndpoint = $"{Prefix}/appliers";
public static readonly string ResumesEndpoint = $"{Prefix}/resumes";
public static readonly string ApplicationsEndpoint = $"{Prefix}/applications";
}
}
I tried adjusting my domain class as well as double-checking my endpoints but nothing worked. Visual Studios also says that there aren't any errors.
I have discovered the error. In my AppliersControllers, at the [HttpGet("{id}")] section, I used GetAll instead of Get. This made it so that I was loading the entire list instead of just the data at the Id.

Validation is not working mvc

I just can`t find out what is wrong. I am trying no to allow setting null values to field, when user tries to do it, it must show message "*", and wait for him to set values, but it doesnot work and null values are successfully sent to an action.
Model :
public class CompanyMainInfoModel
{
public int CompanyId { get; set; }
[Required(ErrorMessage = "*")]
[Display(Name = "company_name", ResourceType = typeof(Localization))]
public string CompanyName { get; set; }
[Required(ErrorMessage = "*")]
[Display(Name = "company_address", ResourceType = typeof(Localization))]
public string CompanyAddress { get; set; }
[Required(ErrorMessage = "*")]
[Display(Name = "company_director", ResourceType = typeof(Localization))]
public string CompanyDirector { get; set; }
[Required(ErrorMessage = "*")]
[Display(Name = "company_phone", ResourceType = typeof(Localization))]
public string CompanyTelephoneNumber { get; set; }
}
Markup :
#model BTGHRM.Models.CompanyMainInfoModel
#{
Layout = "~/Views/Shared/_EmployeeMain.cshtml";
}
<head>
<script src="~/Scripts/jquery-1.10.2.js"></script>
<script src="~/Scripts/jquery-ui.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
</head>
<body>
<span class="content_h4">#Resources.Localization.company_info</span>
<br />
<br />
<div id="FormContainer">
#Html.Partial("Partial/_CompanyInfo", Model)
</div>
</body>
Partial Markup:
#model BTGHRM.Models.CompanyMainInfoModel
#using (Html.BeginForm("CompanyInfo", "Administration"))
{
<table>
<tr>
<td>#Html.LabelFor(m => m.CompanyName)</td>
<td>#Html.TextBoxFor(m => m.CompanyName)</td>
<td>#Html.ValidationMessageFor(m => m.CompanyName, "" , new { #class="text-danger"})</td>
</tr>
<tr>
<td>#Html.LabelFor(m => m.CompanyAddress)</td>
<td>#Html.TextBoxFor(m => m.CompanyAddress)</td>
<td>#Html.ValidationMessageFor(m => m.CompanyAddress, "", new { #class = "text-danger" })</td>
</tr>
<tr>
<td>#Html.LabelFor(m => m.CompanyDirector)</td>
<td>#Html.TextBoxFor(m => m.CompanyDirector)</td>
<td>#Html.ValidationMessageFor(m => m.CompanyDirector, "", new { #class = "text-danger" })</td>
</tr>
<tr>
<td>#Html.LabelFor(m => m.CompanyTelephoneNumber)</td>
<td>#Html.TextBoxFor(m => m.CompanyTelephoneNumber)</td>
<td>#Html.ValidationMessageFor(m => m.CompanyTelephoneNumber, "", new { #class = "text-danger" })</td>
</tr>
</table>
<input style="width:78px" type="submit" value=#Resources.Localization.save />
}
And despite [Required] it still allows me to set null values to any field.
What is wrong with my code?
You have to have unobtrusive scripts enabled in web config
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
Then you need to add
jquery
jquery.validate.js
jquery.validate.unobtrusive.js
You need to add "jquery.validate.js" and "jquery.validate.unobtrusive.js" in your View. Validation needs the above two files along with "Jquery.js". Hope this helps.

Extra parameter is coming with a POST

My model is this a Movie class with this metadata:
[MetadataType(typeof(MovieMetadata))]
public partial class Movie
{
}
class MovieMetadata
{
[ScaffoldColumn(false)]
public int id { get; set; }
[Required(ErrorMessage = "Title is required")]]
[StringLength(70, ErrorMessage = "Title must have a lenght less than 70")]
public string title { get; set; }
[Required(ErrorMessage = "The realese date of the movie is required")]
public DateTime releaseDate { get; set; }
public string storyline { get; set; }
public Binary poster { get; set; }
[ScaffoldColumn(false)]
public Binary trailer { get; set; }
}
My Create View has this code inside:
#using (Html.BeginForm(null, null, FormMethod.Post, new { id = "createForm", enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="gallMemberBox">
<div class="rightFormContent">
<div>
#Html.LabelFor(model => model.title)
#Html.EditorFor(model => model.title)
#Html.ValidationMessageFor(model => model.title)
</div>
<div>
#Html.LabelFor(model => model.releaseDate)
#Html.EditorFor(model => model.releaseDate)
#Html.ValidationMessageFor(model => model.releaseDate)
</div>
<div>
#Html.Label("Poster")
<input name="poster" value="C:" id="poster" type="file" />
</div>
<div>
#Html.Label("Trailer")
#* #Html.TextBox("trailer", "", new { type = "file", id="trailer" })*#
<input name="trailer" value="" id="trailer" type="file" />
</div>
<div>
#Html.LabelFor(model => model.storyline)
#Html.TextAreaFor(model => model.storyline, new{id="storyline"})
</div>
<div>
#Html.Label("Directors")
<select class="chosen-select" multiple="" data-placeholder="Select directors">
#for(int i = 0; i < directors.Count; i ++)
{
<option value="#i">#directors[i].name</option>
}
</select>
</div>
<div>
#Html.Label("Actors")
<select class="chosen-select" multiple="" data-placeholder="Select actors of the Screen">
#for(int i = 0; i < actors.Count; i ++)
{
<option value="#i">#actors[i].name</option>
}
</select>
</div>
<div>
#Html.Label("Writers")
<select class="chosen-select" multiple="" data-placeholder="Select writers of the Film">
#for(int i = 0; i < writers.Count; i ++)
{
<option value="#i">#writers[i].name</option>
}
</select>
</div>
<input type="submit" value="Create" />
</div>
}
I just filled title and releaseDate and click on submit(Create), after that in my ModelState I have three parameters, title, releaseDate and storyline(I never put some value on this one, and the value is an empty string. On the others fields I never put a value and they do not come with that POST. Why? And how to fix this?
public ActionResult Create([Bind(Exclude = "poster, trailer")]Movie movie, HttpPostedFileBase poster, HttpPostedFileBase trailer)
{
Your field storyline will already be available by the id and name "storyline as this is created like by MVC.
Remove the "id" part, or use "#id = ...".
You can write:
<div>
Storyline
#Html.TextAreaFor(model => model.storyline)
</div>

Pass variable to strongly typed form from different view

I'm having a little trouble passing url variables to a form on a separate view. Basically I have a 'HomeController' which has a 'Contact' action and view, and a 'SalesController' which has an action and a view called 'View'.
On the view called 'View' (confusing I know), I have an action link like so:
<a href="#Url.Action("Contact", "Home", new { pid = Model.Property[0].Pid, type = "Viewing"})" class="detailsBtn">
As you can see, this is passing two variables of 'pid' and 'type' to the 'Contact' action of the 'HomeController'. The contact returns a strongly typed view with the following model being used.
public class ContactModel
{
[Required]
[DataType(DataType.Text)]
public string FullName { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
[EmailAddress(ErrorMessage = "Invalid Email Address")]
public string Email { get; set; }
[Required]
[DataType(DataType.PhoneNumber)]
[Phone(ErrorMessage = "Invalid Phone Number")]
public string Telephone { get; set; }
[DataType(DataType.Text)]
public string Address { get; set; }
[Required]
[DataType(DataType.Text)]
public string Subject { get; set; }
[Required]
[DataType(DataType.Text)]
public string Message { get; set; }
}}
Here's the Contact view:
#using (Html.BeginForm())
{
<div class="formField">
<span class="label">Full Name *</span><br />
#Html.TextBoxFor(Model => Model.FullName, new { #class = "txtContact" })
#Html.ValidationMessageFor(Model => Model.FullName, "Full enter your full name")<br/>
</div>
<div class="formField">
<span class="label">Email Address *</span><br />
#Html.TextBoxFor(Model => Model.Email, new { #class = "txtContact" })
#Html.ValidationMessageFor(Model => Model.Email, "Please ensure that a valid email is entered.")<br/>
</div>
<div class="formField">
<span class="label">Telephone *</span><br />
#Html.TextBoxFor(Model => Model.Telephone, new { #class = "txtContact" })
#Html.ValidationMessageFor(Model => Model.Telephone, "Please enter a valid telephone number")<br/>
</div>
<div class="formField">
<span class="label">Property Address (optional)</span><br />
#Html.TextBoxFor(Model => Model.Address, new {#class = "txtContact" })<br />
</div>
<div class="formField">
<span class="label">Subject *</span><br />
#if (ViewBag.Pid != null) {
#Html.TextBoxFor(Model => Model.Subject, new {#class = "txtContact" })
} else {
#Html.TextBoxFor(Model => Model.Subject, new { #class = "txtContact" })
}
#Html.ValidationMessageFor(Model => Model.Subject, "Please enter a subject")<br/>
</div>
<div class="formField">
<span class="label">Message *</span><br />
#Html.TextAreaFor(Model => Model.Message, new { #class = "txtContact" })
#Html.ValidationMessageFor(Model => Model.Message, "Please enter a message")<br/>
</div>
<input type="submit" class="contact-btn" value="Send" />
}
I simply need to know the best way for me to add the 'pid' and 'type' variables passed to the Contact Action from the Action link in the Sales Controller as values for my text boxes in the contact form.
You can always extend your Model to include a PID and Type property.
In your form you could just enter #Html.HiddenFor(Model => model.Pid) and #Html.HiddenFor(Model => model.Type) (or #Html.DisplayFor if you want them visible)
If you didn't want to do that, you could put your PID and Type values into ViewBag or ViewData from the Action, and then put these values into form fields in your view.
Edit:
If you would like the Pid and Type to be part of your strongly typed view, you can change your model to be like the following:
public class ContactModel
{
//all your other properties...
public string ContactType { get; set; }
public string Pid { get; set; }
}
Then in your Contact action, you can:
var model = new ContactModel() { ContactType = type, Pid = pid };
return View(model);

Bind data from db to dropdownlist + ASP.NET MVC

I have a question about using a dropdownlist in ASP.net MVC.
This is my situation:
Create view:
#using (Html.BeginForm("Create", "Deliverable", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>EventViewModel</legend>
<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>
<div class="editor-label">
#Html.LabelFor(model => model.Thumbnail)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.Thumbnail, new { type = "file" })
#Html.ValidationMessageFor(model => model.Thumbnail)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Image)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.Image , new {type="file"})
#Html.ValidationMessageFor(model => model.Image)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.VideoUrl)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.VideoUrl)
#Html.ValidationMessageFor(model => model.VideoUrl)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.VideoUrl)
</div>
<div class="editor-field">
#Html.ValidationMessageFor(model => model.VideoUrl)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
After the 'VideoURL' I would like to have a Dropdownlist with values that are stored in my database. Most of the tutorials that I find don't bind the values in the dropdownlist to the database.
I insert the values in my db in my backoffice so I can't insert them in frontoffice...
This is my Controller:
public ActionResult Create(DeliverableViewModel model)
{
var afstudeerrichtingen = (repository.GetAfstudeerrichtingen()).ToList();
if (ModelState.IsValid)
{
try
{
MemoryStream target = new MemoryStream();
model.Image.InputStream.CopyTo(target);
byte[] data = target.ToArray();
model.Thumbnail.InputStream.CopyTo(target);
byte[] datatwo = target.ToArray();
users usr = userrepo.FindByUsername(User.Identity.Name);
model.UsernameID = usr.user_id;
repository.AddDeliverable(model.Title, model.Description, model.UsernameID, data, datatwo, model.VideoUrl, model.Afstudeerrichting);
}
catch (ArgumentException ae)
{
ModelState.AddModelError("", ae.Message);
}
return RedirectToAction("Index");
}
return View(model);
}
In sent the values to my repository where I save it in my database.
This is my DeliverableViewModel:
public class DeliverableViewModel
{
[Required]
[Display(Name = "Title")]
public string Title { get; set; }
[Required]
[Display(Name = "Description")]
public string Description { get; set; }
[Required]
[Display(Name = "Thumbnail")]
public HttpPostedFileBase Thumbnail { get; set; }
[Required]
[Display(Name = "Image")]
public HttpPostedFileBase Image { get; set; }
[Required]
[Display(Name = "VideoUrl")]
public string VideoUrl { get; set; }
[Required]
[Display(Name = "AfstudeerrichtingID")]
public int AfstudeerrichtingID { get; set; }
[Required]
[Display(Name = "Afstudeerrichting")]
public IEnumerable<SelectListItem> Items { get; set; }
public long UsernameID { get; set; }
}
Does anyone know what I have to add in my view & controller to make this work?
The values are in my tabel "Afstudeerrichtingen" in my mysql database
- afstuddeerichting_id
- afstudeerrichting_name
Add a dropdownlist in your view:
#Html.DropDownListFor(model => model.AfstudeerrichtingID,
new SelectList(ViewBag.Richtingen,
"AfstudeerrichtingId", "AfstudeerrichtingName"))
Add your Afstudeerrichting collection to the ViewBag in the controller:
ViewBag.Richtingen = afstudeerrichtingen;
Assuming that that collection contains the properties AfstudeerrichtingId and AfstudeerrichtingName, as used in the view.
Another thing to do is change your AfstudeerrichtingID to string, and translate it to/from int in your repository class.