I am just attempting to bind a collection from a form post. My collection in the model is a different name than what I'm trying to bind to, which my be the cause of the issue. I had this working, and then it stopped. I cannot find what changed to make it stop.
I thought my question was similar to this one:
ASP.NET MVC5: Want to update several items in Collection with model binding
And I have read this a few times (Scott Hanselman can be counted on to give a clear picture of such things):
http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx
Here's some code:
public class AttestModel
{
public Account Account { get; set; }
public List<AccountSimpleDetail> AccountSimpleDetails { set; get; }
}
public class AccountSimpleDetResponseModel
{
public int AccountSimpleDetailId { get; set; }
public int AnswerId { get; set; }
}
public partial class AccountSimpleDetail :
{
public int AccountSimpleDetailId { get; set; }
public int? SaqSimpleQuestionId { get; set; }
public int? SaqAnswerId { get; set; }
...More fields go on here
}
In the View I have:
#for (var i = 0; i < Model.AccountSimpleDetails.Count(); i++)
{
#Html.HiddenFor(x => x.AccountSimpleDetails[i].AccountSimpleDetailId)
#Html.HiddenFor(x => x.AccountSimpleDetails[i].AnswerId)
}
I have some Javascript to handle clicking on a bunch of buttons in the browser which sets the AnswerId in the hidden fields. This is working fine.
The markup produced looks like this:
<input data-val="true" data-val-number="The field AccountSimpleDetailId must be a number." data-val-required="The AccountSimpleDetailId field is required." id="AccountSimpleDetails_1__AccountSimpleDetailId" name="AccountSimpleDetails[1].AccountSimpleDetailId" type="hidden" value="71" />
<input data-val="true" data-val-number="The field AnswerId must be a number." id="AccountSimpleDetails_1__AnswerId" name="AccountSimpleDetails[1].AnswerId" type="hidden" value="1" />
The method signature looks like this:
public ActionResult Attest(int id, List<AccountSimpleDetResponseModel> AccountSimpleDetails)
What I used previously (which stopped working) is:
public ActionResult Attest(int id, [Bind(Prefix = "AccountSimpleDetails")] List<AccountSimpleDetResponseModel> simpleDetails)
The result of the bind is always null.
I know when I get to the point where I try something, it doesn't work, I try something else... it simply means I am missing some fundamental point. Thank you for your time.
EDIT
Here is the post request (Raw from Watchlist):
AccountSimpleDetails%5b1%5d.AccountSimpleDetailId=165&AccountSimpleDetails%5b1%5d.AnswerId=1&AccountSimpleDetails%5b2%5d.AccountSimpleDetailId=166&AccountSimpleDetails%5b2%5d.AnswerId=1&AccountSimpleDetails%5b3%5d.AccountSimpleDetailId=167&AccountSimpleDetails%5b3%5d.AnswerId=1&AccountSimpleDetails%5b4%5d.AccountSimpleDetailId=168&AccountSimpleDetails%5b4%5d.AnswerId=1&DXScript=1_171%2c1_94%2c1_93%2c17_33%2c17_2%2c1_152%2c1_164%2c1_91%2c1_156%2c1_101%2c17_7%2c1_154%2c1_103%2c1_102%2c17_8%2c1_114%2c1_121%2c1_169%2c1_138%2c1_170%2c1_124%2c17_9%2c1_163%2c1_162%2c1_147%2c17_32%2c1_157%2c1_98%2c1_125%2c1_104%2c1_166%2c1_139%2c17_13%2c1_97%2c1_141%2c1_142%2c17_15%2c1_155%2c1_143%2c1_144%2c17_16%2c17_17%2c1_126%2c17_11%2c1_146%2c1_149%2c17_20%2c1_160%2c17_22%2c1_158%2c1_153%2c1_161%2c17_25%2c1_165%2c17_28%2c17_31%2c1_100%2c5_5%2c5_4%2c4_11%2c4_10%2c4_6%2c4_7%2c4_9%2c17_14%2c4_12%2c1_113%2c1_116%2c4_13%2c4_14%2c1_110%2c1_112%2c1_137%2c17_12%2c1_159%2c7_49%2c7_47%2c7_51%2c17_21%2c1_105%2c1_108%2c1_117%2c17_0%2c1_120%2c1_106%2c17_1%2c1_107%2c17_3%2c1_109%2c1_122%2c17_5%2c1_145%2c1_119%2c17_18%2c17_19%2c1_118%2c17_29%2c1_123%2c10_2%2c10_1%2c10_3%2c10_4%2c17_4%2c9_23%2c9_22%2c9_24%2c17_24%2c9_13%2c9_10%2c9_8%2c17_23%2c9_12%2c9_9%2c9_15%2c9_11%2c1_96%2c8_10%2c8_17%2c8_24%2c8_26%2c8_9%2c8_12%2c8_13%2c8_18%2c17_26%2c8_21%2c8_23%2c8_22%2c8_16%2c8_19%2c8_20%2c8_14%2c8_15%2c8_25%2c8_11%2c6_12%2c17_30%2c16_16%2c16_18%2c16_14%2c16_11%2c16_19%2c16_6%2c16_15%2c16_8%2c16_12%2c16_13%2c16_7%2c17_27%2c16_17&DXCss=http%3a%2f%2ffonts.googleapis.com%2fcss%3ffamily%3dOpen%2bSans%3a300%2c400%2c600%2c700%2c800%257CShadows%2bInto%2bLight%2c%2fContent%2fbootstrap.min.css%2c%2fContent%2fMainSite.css%2c%2fContent%2fSiteAdjustments.css%2c%2fContent%2ffont-awesome.min.css%2c1_12%2c1_14%2c0_863%2c0_859%2c1_10%2c0_695%2c1_5%2c0_697%2c0_703%2c0_706%2c0_823%2c0_813%2c0_861%2c0_709%2c4_2%2c0_711%2c5_1%2c0_794%2c0_776%2c0_778%2c7_1%2c7_0%2c1_1%2c0_671%2c9_18%2c9_19%2c9_21%2c9_20%2c0_888%2c9_17%2c0_890%2c0_790%2c8_2%2c0_792%2c8_0%2c0_810%2c6_2%2c0_812%2c0_796%2c16_2%2c0_798
You binding your controls to properties of AttestModel so just post back the model
public ActionResult Attest(AttestModel model)
and the AccountSimpleDetails property will be correctly bound to the collection. However looking at your edited post request, it appears that the indexers are starting at 1, not 0 (i.e. the first one is AccountSimpleDetails[1].AccountSimpleDetailId=165.... Do you have any javascript that deletes items in the collection? If so it will not bind the collection because indexers are zero based (and must be consecutive) so you will need to add an additional control for the index property.
I have this:
#for (int x = 0; x < Model.AccountSimpleDetails.Count(); x++)
{
<span>#x</span>
}
And it returns:
1,2, 3
That is the reason for the parsing issues as Stephen pointed out. So that's the real issue.
Thanks
Related
I'm working on a search criteria building page. In addition to several string and numerical type fields, there are several "multiple choice" options.
I'm using the [Get] signature without parameters(pass the CriteriaModel to the view) >> [Post] signature with CriteriaModel parameter (redirect to searching controller)
I've built lightweight option classes (just value, name pairs) and am populating several List<> with the primitive options.
Using Html.DropDownListFor, I'm able to get them to display.
...but...
When I enter the [Post] version, the List<>s are all set to null and empty. Further, the other criteria fields supposed to be populated afterwards are also default and empty.
Technically, I don't need a whole list of values back - if I could even just have the index of the selected value - but I'm up against a wall here.
Pertinent model data:
public class CriteriaModel
{
[DisplayName("Owner Name")]
public string OwnerName { get; set; }
[DisplayName("Subdivision")]
public List<Subdivision> Subdivision { get; set; }
[DisplayName("PIN")]
public string PIN { get; set; }
}
public class Subdivision
{
public int ID { get; set; }
public string Name { get; set; }
}
Pertinent controller code:
[HttpGet]
public ActionResult Index()
{
CriteriaModel criteria = new CriteriaModel();
...fill in the Subdivisions...
View(criteria);
}
[HttpPost]
public ActionResult Index(CriteriaModel search_criteria)
{
return View("Search obtained" + search_criteria.Subdivision.First().Name);
}
And pertinent View markup:
#model REOModern.Models.CriteriaModel
...bunch of HTML...
#Html.LabelFor(model => model.Subdivision)
#Html.DropDownListFor(x => x.Subdivision, new SelectList(Model.Subdivision, "ID", "Name", Model.Subdivision.First().ID))
...other HTML...
<button type="submit" class="btn btn-primary" value="Index">Search</button>
I should clarify: I know that my 'return View("Search obtained" + ...' will fail, but it should show the piece of data that I need. The problem is it's a null reference exception. Until I can fix that, there's no point in building a user-friendly View for submitted search criteria.
MVC does not repopulate the List<> elements.
You would split the selected value out into another property of the model.
So in your model, include something like this
public int SelectedValue { get; set; }
Then for your Html.DropDownListFor helper you would use
Html.DropDownListFor(model => model.SelectedValue, Model.DropDownList, new { /* htmlAttributes */ });
Of course they're empty. The only data that exists in your post action is that which was posted via the form. Since the entire dropdown list, itself, was not posted, merely a selected item(s), the lists are empty. For anything like this, you need to rerun the same logic in your post action to populate them as you did in your get action. It's usually better to factor out this logic into a private method on your controller that both actions can use:
private void PopulateSomeDropDownList(SomeModel model)
{
// logic here to construct dropdown list
model.SomeDropDownList = dropdownlist;
}
Then in your actions:
PopulateSomeDropDownList(model);
return View(model);
Let's imagine I have the following situation:
I have a question form and I want to add answer choices to it (my user should be allowed to add as many choices as he wants).
So I have this ViewModel (being sent to the view).
public class QuestionEdit
{
public int Id { get; set; }
[Required]
[StringLength(200)]
public string Question { get; set; }
public List<Choice> Choices { get; set; }
}
public class Choice
{
public int Id { get; set; }
[Required]
[StringLength(200)]
public string Choice { get; set; }
public bool Correct {get; set;^}
}
My Controller's Edit Post looks like this:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Id,Question,Choices")] QuestionEdit vm)
{
if (ModelState.IsValid)
{
/*Removed for clarity*/
}
return View(vm)
}
Is there any way of me getting the content from Choices and converting it to a javascript list, changing it as my user adds or removes items only by using javascript/ajax and when submitting the form, would it be a way for me to adding it back as if it were the Choices that my controller will be able to read?
I am aware that I could use the an custom EditorFor for this List, but everytime someone adds a new Choice I would have to post the entire form to add it and them get it back, so I wanted to change this only through javascript, as it requires only simple validations (not needing any server/database validation).
Thanks a lot.
You can use as much JavaScript and ajax as you need, as long as in your form you have inputs that are named in a way that the model binder expects.
What I mean by that is, you can create form inputs with a name attribute in the form of:
<input type="text" name="Choices[0].Id" />
<input type="text" name="Choices[0].Choice" />
<input type="hidden" name="Choices[0].Correct" />
<input type="text" name="Choices[1].Id" />
<input type="text" name="Choices[1].Choice" />
<input type="hidden" name="Choices[1].Correct" />
And so on. When you post your form, the model binder will attempt to take whatever values are attached and set them on your QuestionEdit object based on the name. So in the above case, vm.Choices in your action method will contain 2 items.
This link gives some pretty good examples that should point you in the right direction:
http://www.codeproject.com/Articles/551576/ASP-NET-MVC-Model-Binding-and-Data-Annotation
From there, it's up to your JavaScript to create input elements accordingly and append them to your form.
Hope this helps.
EDIT v2: - SOLVING STEP
Wrote custom ModelBinder and now it works. Additionally I tryed out and noticed, that it would work with the Default ModelBinder if the Boolean value is parsed into the hidden input as string ("boolean.toString()").
But with the Deafault ModelBinder I wouldn't have catched this.
EDIT v1:
I have might have moved on by adding hidden inputs of the remaining fields. Now it appears to not bind the form values with the model properly...
From what I understand the Default Binder, when I've got ALL field names named same as the form input name attributes (int season ....
I might need to write my own binder, but than that Model elegance, which I so much expect, goes out of the window.
Still there might be better for me so far unknown solution. Any suggestions and help appreciated.
ORIGINAL:
Got an issue regarding creation and being able to construct my own edit action in which I will change only few attributes (in this case the season and the episode fields) and I want it to work with the model, not its single fields.
I got this model...
public class Entry
{
public int entryID { get; set; }
[Required]
[Range(0, 99)]
public int season { get; set; }
[Required]
[Range(0, 99)]
public int episode { get; set; }
[Required]
public Boolean button_dark { get; set; }
[Required]
public int showID { get; set; }
public virtual Show show { get; set; }
public int? pictureID { get; set; }
public virtual Picture picture { get; set; }
public Entry () {
season = 0;
episode = 0;
}
}
... and I got classic GET and POST actions in the controller...
public ActionResult Index(int id)
{
Entry entry = db.Entries.Find(id);
if (entry == null)
{
return HttpNotFound();
}
return View(entry);
}
[HttpPost]
public ActionResult Index(Entry entry)
{
if (ModelState.IsValid)
{
db.Entry(entry).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Home");
}
return View(entry);
}
... and in the view I essentialy have.
<form action="/Entry/Index/#Model.entryID" method="post">
<input type="number" name="season" value="#Model.season" />
<input type="number" name="episode" value="#Model.episode"/>
<input class="button" type="submit" value="Submit" />
</form>
From what I have read about the Model Binder, it shoud chew it just ok. (I hope I did't missinterpreted or missunderstood anything)
When submiting the form i get this exception at the "db.SaveChanges();" statement.
System.Data.Entity.Infrastructure.DbUpdateConcurrencyException was unhandled by user code
HResult=-2146233087
Message=Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
I know what it says, but don't know why. And as a quite newbie in the .NET MVC I don't understand other forum posts to the exception itself.
Does anyone PLEASE know where and what should I do or read to help me with that?
Many thanks.
OK, now I will summarize this, for me a little unintuitive, solution to my problem...
You need to have all model fields in the form (even if they were
hidden)
Be sure to insert right data types in the input values,
otherwise the binder won't bind succesfully data to the model (for
example: Boolean must go there as String)
Using my model displaying a page works fine but the post does not return the bound model.
My classes:
public class ContactManager
{
public Contact Contact { get; set; }
public SelectList SalutationList { get; set; }
}
public class Contact
{
public int Id{get;set;}
public string FirstName{get; set;}
public SalutationType SalutationType{get; set;}
}
public class SalutationType
{
public int Id { get; set; }
public string Name { get; set; }
}
My View:
#model ViewModels.ContactManager
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.Contact.Id)
#Html.DropDownListFor(model => model.Contact.SalutationType.Id, Model.SalutationList)
#Html.EditorFor(model => model.Contact.FirstName)
<input type="submit" value="Save" />
}
The issue seems to be in the DropDownListFor. The dropdown list displays correctly with the proper value but when I post this page the complete model is blank. If I simplify the DropDownListFor like this the values are posted as expected.
#html.DroDownListFor(model=>model.MyPlaceHolderProp, Model.SalutationList)
Is my model too complex? Am I not doing something correctly?
The models are based off of several tables using EF that I have created in a separate project. I am trying to avoid creating more classes/models then I have to.
You should post your controller action as well, as your model coming back as blank really has nothing to do with this. Changing the DropDownListFor definition one way or another should not effect the posting of any other values.
That said, you will run into another issue eventually here, so you need to regroup, anyways. You can't just post back the id value of a related item. Entity Framework will either complain that there's already an object with that id, or worse, if the object attaches, it will update the row with that id with the new posted value for Name, which in this case, is nothing, so it'll just clear it out.
When you create a relationship with a single item (a foreign key basically), if you don't specify a property to hold that foreign key value, Entity Framework creates one for you behind the scenes to track the relationship. In your case here, that means your Contacts table has a column named SalutationType_Id. However, there's no way from your class to directly access this value. This is why I recommend that you always provide an explicit property to handle the relationship:
[ForeignKey("SalutationType")]
public int SalutationTypeId { get; set; }
public SalutationType SalutationType { get; set; }
If you do that, then you can directly stuff the posted id there and Entity Framework will create the relationship.
#Html.DropDownListFor(m => m.Contact.SalutationTypeId, Model.SalutationList);
If you insist on keeping the key implicit, then you must create the relationship yourself, by creating a field on your view model to hold the posted value, then using that value to look up the SalutationType instance from the database, and then finally adding that to the Contact instance.
Add to your view model
public int SalutationTypeId { get; set; }
In your view
#Html.DropDownListFor(m => m.SalutationTypeId, Model.SalutationList)
In your POST action
var salutationType = db.SalutationTypes.Find(model.SalutationTypeId);
contact.SalutationType = salutationType;
You could do it this way. This may be the more "MVC best practice" way to handle it. Everything stays neatly in their models, and no manual IDs are required. The views are intended to be representations of the underlying models they are built on. If you are creating a view that has a form, then create a model that represents the form and use it in the view.
Revise your models like:
public class PostModel
{
public int ContactID { get; set; }
public int SalutationID { get; set; }
public string FirstName { get; set; }
}
public class PostView
{
public ContactManager contact { get; set; }
public PostModel post { get; set; }
}
Then create the PostView in the controller:
public ActionResult Index()
{
//create the PostView model
var pv = new PostView();
pv.ContactManager = contactManager;
pv.post = new PostView()
{
ContactID = contactManager.Contact.Id,
SalutationID = contactManager.SalutationType.Id,
FirstName = contactManager.Contact.FirstName
};
return View(pv);
}
Then the view could be like:
#model ViewModels.PostView
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.post.ContactID)
#Html.DropDownListFor(model => model.post.SalutationID, model.contact.SalutationList)
#Html.EditorFor(model => model.post.FirstName)
<input type="submit" value="Save" />
}
Then the post action in the controller:
[HttpPost]
public ActionResult Index(PostView pv)
{
//post code
//the posted data will be in pv.post
}
Have you considered using a custom model binder? Custom model binding isn't all that complicated for models that are still relatively simple, and you can handle the serialization/deserialization however you need to.
http://msdn.microsoft.com/en-us/magazine/hh781022.aspx
http://ivonna.biz/blog/2012/2/2/custom-aspnet-model-binders-series,-part-3-subclassing-your-models.aspx
http://forums.asp.net/t/1944696.aspx?what+is+custom+model+binding+in+mvc
I am not sure this will help you... I wsa having a similar issue but I was using ajax to post back... anyway, I had forgotten to mark my binding class with the [Serializable] attribute.
so you might try
[Serializable]
public class Contract {
...
}
Again, I am using Json to post back to my controller so may not be related or help you. But, I guess could be worth a try.
I'm populated a partial view with a strongly-typed model. In this partial view is a form. When I submit the form it tells me that objects inside of my model are null, even though they are not because the partial view rendered all elements based on that same model.
More specifically, I'm having trouble passing back all of my checkboxes. If you look at my controller you can see that I check to see if CompanyOptions is null, and every time I run the program it prints STUFF IS NULL, meaning that it's null.
Model:
public class Company
{
public string Name { get; set; }
public string DatabaseName { get; set; }
public CompanyOptions CompanyOptions;
}
public class CompanyOptions
{
public CompanyLicenseOptions CompanyLicenseOptions { get; set; }
}
public class CompanyLicenseOptions
{
public List<CompanyLicenseOption> CompanyLicenseOptionsList;
}
View:
#using (Html.BeginForm("Action", FormMethod.Post))
{
for (int i = 0; i < Model.CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList.Count; i++)
{
#Html.CheckBoxFor(model => model.CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[i].IsLicensed, checkboxHtmlAttributes);
<label for="#Model.CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[i].LicenseName">#Model.CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[i].LicenseName</label>
<br/>
}
#Html.HiddenFor(model => model.DatabaseName)
<input id="submit_licenses" type="submit" style="display:none;" />
}
Controller:
[HttpPost]
public void Action(Company model)
{
System.Diagnostics.Debug.WriteLine("STUFF:" + model.DatabaseName);
if(model.CompanyOptions!=null)foreach (var item in model.CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList) System.Diagnostics.Debug.WriteLine("STUFF:" + item);
else System.Diagnostics.Debug.WriteLine("STUFF IS NULL");
}
Generated HTML:
<input class="licenses" data-val="true" disabled="" id="CompanyOptions_CompanyLicenseOptions_CompanyLicenseOptionsList_0__IsLicensed" name="CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[0].IsLicensed" type="checkbox" value="true" /><input name="CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[0].IsLicensed" type="hidden" value="false" />
The Irrelevant JS
$('#save_licenses').click(function () {
swap_licenses(true);
$('#submit_licenses').click();
});
POST:
Request URL:http://localhost:3080/Controller/Action
Request Method:POST
Status Code:200 OK
CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[0].IsLicensed:false
CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[1].IsLicensed:false
CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[2].IsLicensed:false
CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[3].IsLicensed:false
CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[4].IsLicensed:false
CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[5].IsLicensed:false
CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[6].IsLicensed:false
CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[7].IsLicensed:false
CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[8].IsLicensed:false
CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[9].IsLicensed:false
CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[10].IsLicensed:false
CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[11].IsLicensed:false
CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[12].IsLicensed:false
DatabaseName:myDb
<input class="licenses" data-val="true" disabled="" id="CompanyOptions_CompanyLicenseOptions_CompanyLicenseOptionsList_0__IsLicensed" name="CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[0].IsLicensed" type="checkbox" value="true" /><input name="CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList[0].IsLicensed" type="hidden" value="false" />
Here's your problem:
disabled=""
Your checkbox is disabled, so nothing will ever get sent to the server. That's how HTML works. Disabled elements are never sent. So get rid of this attribute.
If you want to prevent the user from modifying the value, and yet the initial value get sent to the server use the readonly attribute, not disabled.
Also another problem I see with your code is with the CompanyLicenseOptionsList collection field. It should be a property with public getter and setter:
public class CompanyLicenseOptions
{
public List<CompanyLicenseOption> CompanyLicenseOptionsList { get; set; }
}
Same stands true for your CompanyOptions field (you have defined it as a field, whereas it should be a property):
public class Company
{
public string Name { get; set; }
public string DatabaseName { get; set; }
public CompanyOptions CompanyOptions { get; set; }
}
UPDATE:
Now that you have fixed the problem with your missing getters and setters, all that's left is make sure that all the models intervening in this object graph have default (parameterless) constructors. That's a requirement if you want they to appear as action argument because otherwise the default model binder wouldn't know how to instantiate them. If for some reason you cannot add a default constructor to all your objects, I would very strongly recommend you revise your object hierarchy and start using view models right away.
You should use a foreach loop instead of a simple for, this way:
#using (Html.BeginForm("Action", FormMethod.Post))
{
foreach (var option in Model.CompanyOptions.CompanyLicenseOptions.CompanyLicenseOptionsList)
{
#Html.CheckBoxFor(o => o.IsLicensed, checkboxHtmlAttributes);
<label for="#option.LicenseName">#option.LicenseName</label>
<br/>
}
#Html.HiddenFor(model => model.DatabaseName)
<input id="submit_licenses" type="submit" style="display:none;" />
}
Since the endpoint of all these checkboxes is a List<T>, you'll need to make sure that it is instantiated before use:
public class CompanyOptions
{
public CompanyLicenseOptions CompanyLicenseOptions { get; set; }
}
public class CompanyLicenseOptions
{
public List<CompanyLicenseOption> CompanyLicenseOptionsList;
public CompanyLicenseOptions()
{
CompanyLicenseOptionsList = new List<CompanyLicenseOption>();
}
}
EDIT: To ensure that readers get proper context for this answer and avoid confusion, I've reproduced the OP code above mine.