Model Binding is not working, parameter "model" is showing null in the Create Method while debugging [duplicate] - asp.net-mvc

I am just trying to learn MVC and facing some issues.When I am submitting my partial view, I am getting null in Model Blog inside Create Method.
What I am doing wrong and what is the right approach?
View(Index.cshtml)
#model IEnumerable<Samples.Controllers.Blog>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>Sample</th>
<th>URL</th>
<th>Name</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
<td>
#item.URL
</td>
<td>
#item.Name
</td>
</tr>
}
</table>
#Html.Partial("_CreateBlog", new Samples.Controllers.Blog())
Partial View(_CreateBlog.cshtml)
#model Samples.Controllers.Blog
#using (Html.BeginForm("Create","Sample",FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Blog</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="row">
#Html.LabelFor(model => model.URL)
#Html.EditorFor(model => model.URL)
</div>
<div class="row">
#Html.LabelFor(model => model.Name)
#Html.EditorFor(model => model.Name)
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
SampleController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Samples.Controllers
{
public class SampleController : Controller
{
List<Blog> lstBlogs;
public SampleController()
{
lstBlogs = new List<Blog>
{
new Blog{ Name="Domnic", URL= "www.google.com"},
new Blog{ Name="Tom", URL= "www.YAHOO.com"},
new Blog{ Name="Cat", URL= "www.facebook.com"},
new Blog{ Name="Bob", URL= "www.twitter.com"}
};
}
// GET: Sample
public ActionResult Index()
{
return View(lstBlogs);
}
public ActionResult IndexWithDynamicView()
{
return View(lstBlogs);
}
[HttpPost]
public void Create(Blog blog)
{
}
}
public class Blog
{
public string Name;
public string URL;
}
}

Your class Blog only contains fields, not properties so the DefaultModelBinder cannot set their values. Change it add getters/setters
public class Blog
{
public string Name { get; set; }
public string URL { get; set; }
}

Maybe this answer relates to your question: Is there a reason why the default modelbinder doesn't bind to fields?
Pay attention at DefaultModelBinder, ModelBinderContext, ModelMetadata. This explains it all.

Related

ASP.NET MVC Send List from View to controller

I'm trying to create a product model with ID,Name and a list of specifications like above:
My model:
public class Product
{
public int ProductID { get; set; }
public string Name { get; set; }
public virtual List<Spec> Specifications { get; set; }
}
public class Spec
{
public int SpecID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
My Controller:
public ActionResult Create(Product product,List<Spec> Specifications)
{
......
}
My View:
using (Html.BeginForm("Create", "Products", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Product</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-2"><h3>Specifications</h3></div>
<div class="col-md-10">
<table id="tblSkills" cellpadding="0" cellspacing="0" class="table table-responsive">
<thead>
<tr>
<th style="width:150px">Name</th>
<th style="width:150px">Description</th>
<th></th>
</tr>
</thead>
<tbody></tbody>
<tfoot>
<tr>
<td><input type="text" id="Name1" /></td>
<td><input type="text" id="Description" /></td>
<td>
<input type="button" id="btnAdd" class="btn btn-success btn-sm" value="Add" />
</td>
</tr>
</tfoot>
</table>
<br />
<input type="button" id="btnSave" value="SaveAll" class="bntbtn-block btn-success" />
<br />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
so it should looks like this:
I also added some Scripts so that I can enter or remove specifications, the information will be displayed inside a tbody tag in a table.
The problem is that I don't really know how to pass my list of specifications to my controller, or should I try another way of input multiple specifications instead of using table. I'm looking for a way to input it using HTMLHelper like the one I did with Product's Name.
I apologize if my question is unclear. If you have any question to understand more, feel free to ask me. Thanks for any advise or solution.
To pass the model to a view from controller you need to:
public ActionResult Create(List<Spec> Specifications)
{
return View(Specifications);
}
and in your view add these to on top of the view:
#using PathOfYourSpecificationsModel
#model List<Spec>
using (Html.BeginForm("Create", "Products", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Product</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-2"><h3>Specifications</h3></div>
<div class="col-md-10">
<table id="tblSkills" cellpadding="0" cellspacing="0" class="table table-responsive">
<thead>
<tr>
<th style="width:150px">Name</th>
<th style="width:150px">Description</th>
<th></th>
</tr>
</thead>
<tbody></tbody>
<tfoot>
<tr>
<td><input type="text" id="Name1" /></td>
<td><input type="text" id="Description" /></td>
<td>
<input type="button" id="btnAdd" class="btn btn-success btn-sm" value="Add" />
</td>
</tr>
</tfoot>
</table>
<br />
<input type="button" id="btnSave" value="SaveAll" class="bntbtn-block btn-success" />
<br />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
After user clicks add button you need another [HttpPost] method for Create. Which should look like this:
[HttpPost]
public ActionResult Create(List<Spec> Specifications)
{
// Specifications should be filled with view values.
// Do your logic here. Ex: Save the data to database
}
For adding dynamic control fields, it is advised to use helper methods.
The AddNewRow helper method will return the html elements can one can make changes like changing the html attributes.
the html attributes should be unique and it is advised to use increment value for each element.
the attributes of html elements returned from helper method are changed in addNewRow() of javascript function.
Detailed steps are provided below.
In Product Model
public class Product
{
public int ProductID { get; set; }
public string Name { get; set; }
public List<Spec> Specifications { get; set; }
}
public class Spec
{
public int SpecID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool IsRemoved { get; set; }
}
In Controller
public class ProductController : Controller
{
// GET: Product
public ActionResult AddProduct()
{
Product product = new Product();
product.Specifications = new List<Spec>()
{
new Spec()
};
return View(product);
}
[HttpPost]
public ActionResult AddProduct(Product product)
{
return View(product);
}
}
In AddProduct.cshtml
#model Product
#using WebApplication3.Models
#{
ViewBag.Title = "AddProduct";
}
#helper AddNewRow()
{
<tr id="trRow_0">
<td>
#Html.HiddenFor(x => Model.Specifications[0].IsRemoved, new { id = "hdnSpecIsRemoved_0" })
#Html.TextBoxFor(x => Model.Specifications[0].Name, new { id = "txtSpecName_0" })
</td>
<td>
#Html.TextBoxFor(x => Model.Specifications[0].Description, new { id = "txtSpecDesc_0" })
</td>
<td>
Remove Row
</td>
</tr>
}
<h2>AddProduct</h2>
#using (Html.BeginForm("AddProduct", "Product", FormMethod.Post))
{
<div>
#Html.LabelFor(x => x.Name)
#Html.TextBoxFor(x => x.Name)
</div>
<table>
<thead>
<tr>
<th>
#Html.LabelFor(x => x.Specifications[0].Name)
</th>
<th>
#Html.LabelFor(x => x.Specifications[0].Description)
</th>
<th>
Action
</th>
</tr>
</thead>
<tbody id="tBody">
#for (int i = 0; i < Model.Specifications.Count; i++)
{
string trRow = "trRow_" + i;
<tr id="#trRow">
<td>
#Html.HiddenFor(x => Model.Specifications[i].IsRemoved, new { id = "hdnSpecIsRemoved_" + i })
#Html.TextBoxFor(x => Model.Specifications[i].Name, new { id = "txtSpecName_" + i })
</td>
<td>
#Html.TextBoxFor(x => Model.Specifications[i].Description, new { id = "txtSpecDesc_" + i })
</td>
<td>
Remove Row
</td>
</tr>
}
</tbody>
<tfoot>
<tr>
<td colspan="2">
<br />
<button type="button" onclick="addNewRow()">Add New Row</button>
</td>
</tr>
</tfoot>
</table>
<br />
<button type="submit">Save All</button>
}
<script type="text/javascript">
function addNewRow() {
var totalSpecCount = $('#tBody tr').length;
var newRowData = `#(AddNewRow())`;
newRowData = newRowData.replaceAll("Specifications[0]", "Specifications[" + totalSpecCount + "]")
newRowData = newRowData.replaceAll("txtSpecName_0", "txtSpecName_" + totalSpecCount);
newRowData = newRowData.replaceAll("txtSpecDesc_0", "txtSpecDesc_" + totalSpecCount);
newRowData = newRowData.replaceAll("trRow_0", "trRow_" + totalSpecCount);
newRowData = newRowData.replaceAll("removeRow(0)", "removeRow(" + totalSpecCount+")");
newRowData = newRowData.replaceAll("hdnSpecIsRemoved_0", "hdnSpecIsRemoved_" + totalSpecCount);
$('#tBody').append(newRowData);
}
function removeRow(recordId) {
var trId = "#trRow_" + recordId;
var hdnSpec = "#hdnSpecIsRemoved_" + recordId;
$(hdnSpec).val(true);
$(trId).hide();
}
</script>
Here, the method addNewRow will call the helper methods and change the html attributes of the element based on row count.
In strongly typed view, the index values should unique for the list so that it can be posted using model binding
Final Result
Note: In remove row method we have to hide the element instead of removing the element completely. This is used to achieve post the list directly. To know what the rows that are removed a flag called IsRemoved is to true.
If we remove the element, the index value will not be in sequence and one cannot post the form.

MVC AD search - Displaying multiple results as .cshtml

I have fully working code that searches active directory and displays it with MVC .cshtml But I have been trying to figure out away to add all the users found to a list then display them. As currently it just displays the first user found.
This is the HomeController that takes a value, Searches AD and returns the results.
public class HomeController : Controller
{
public ActionResult Index(IndexViewModel profile)
{
if (ModelState.IsValid)
{
//List<Principal> users = new List<Principal>();
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
UserPrincipal qbeUser = new UserPrincipal(ctx);
qbeUser.DisplayName = profile.Name + "*";
using (PrincipalSearcher srch = new PrincipalSearcher(qbeUser))
{
if(!(srch.FindAll().Count() < 0))
{
foreach(var found in srch.FindAll())
{
//users.Add(found);
IndexViewModel returnmodel = new IndexViewModel(found);
return View(returnmodel);
}
}
}
}
}
return View(profile);
}
}
The IndexViewModel
public class IndexViewModel
{
public IndexViewModel(Principal found)
{
Name = found.DisplayName;
Email = found.UserPrincipalName;
Description = found.Description;
}
[Required(ErrorMessage = "Please enter a name")]
[Display(Name = "Persons Name")]
public string Name { get; set; }
public string Email { get; set; }
public string Description { get; set; }
//public List<Principal> user { get; set; }
}
Index.cshtml
<div id="content">
#Html.ValidationSummary(true)
#using (Html.BeginForm("Index", "Home"))
{
<fieldset>
<div class="form-group col-md-12">
#Html.LabelFor(model => model.Name, new { #class = "control-label col-md-2" })
<div class="col-md-4">
#Html.EditorFor(modelItem => Model.Name, new { htmlAttributes = new { #class = "form-control", #style = "width:280px" }, })
#Html.ValidationMessageFor(x => x.Name)
</div>
<div class="col-md-2">
<input type="submit" class="btn btn-default" value="Search">
</div>
<div class="col-md-3">
</div>
</div>
</fieldset>
}
<br>
</div>
<table id="historyTable" class="table">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>#Model.Name</td>
<td>#Model.Email</td>
<td>#Model.Description</td>
</tr>
</tbody>
</table>
EDIT-----------
This is one method I tried ----------------
HomeController.cs
public class HomeController : Controller
{
public ActionResult Index(IndexViewModel profile)
{
if (ModelState.IsValid)
{
List<Principal> users = new List<Principal>();
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
UserPrincipal qbeUser = new UserPrincipal(ctx);
qbeUser.DisplayName = profile.Name + "*";
using (PrincipalSearcher srch = new PrincipalSearcher(qbeUser))
{
if(!(srch.FindAll().Count() < 0))
{
foreach(var found in srch.FindAll())
{
users.Add(found);
IndexViewModel returnmodel = new IndexViewModel(users);
return View(returnmodel);
}
}
}
}
}
return View(profile);
}
IndexViewModel.cs
public class IndexViewModel
{
public IndexViewModel(List<Principal> found)
{
user = found;
}
[Required(ErrorMessage = "Please enter a name")]
[Display(Name = "Persons Name")]
public string Name { get; set; }
public string Email { get; set; }
public string Description { get; set; }
public List<Principal> user { get; set; }
}
index.html
<div id="content">
#Html.ValidationSummary(true)
#using (Html.BeginForm("Index", "Home"))
{
<fieldset>
<div class="form-group col-md-12">
#Html.LabelFor(model => model.Name, new { #class = "control-label col-md-2" })
<div class="col-md-4">
#Html.EditorFor(modelItem => Model.Name, new { htmlAttributes = new { #class = "form-control", #style = "width:280px" }, })
#Html.ValidationMessageFor(x => x.Name)
</div>
<div class="col-md-2">
<input type="submit" class="btn btn-default" value="Search">
</div>
<div class="col-md-3">
</div>
</div>
</fieldset>
}
<br>
</div>
<table id="historyTable" class="table">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Description</th>
</tr>
</thead>
<tbody>
#using System.DirectoryServices.AccountManagement
#foreach (Principal prin in Model.user)
{
<tr>
<td>#prin.DisplayName</td>
<td>#prin.UserPrincipalName</td>
<td>#prin.Description</td>
</tr>
}
</tbody>
</table>
The error I get on compile is --
Object reference not set to an instance of an object.
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.NullReferenceException: Object reference not set to an instance of an object.
Source Error:
Line 37: <tbody>
Line 38: #using System.DirectoryServices.AccountManagement
Line 39: #foreach (Principal prin in Model.user)
Line 40: {
Line 41: <tr>
Source File: C:\Users\hga\Documents\Visual Studio 2015\Projects\Intra AD people searcher\Intra AD people searcher\Views\Home\Index.cshtml Line: 39
You can add if statement to check for null
#if(Model.user !=null)
{
#foreach (Principal prin in Model.user)
{
<!--your code here-->
}
}
In your controller, your return statement is inside your foreach loop. So the first time it goes through the loop, it will return. That means you will only have one result.
Try this:
foreach(var found in srch.FindAll())
{
users.Add(found);
}
IndexViewModel returnmodel = new IndexViewModel(users);
return View(returnmodel);

How to get data from partial in form

I have
ASP.NET MVC Form in popup with some controls and partial (data grid) with his own Model.
here is popup:
<div id="AddEditDialog" class="none">
#using (Ajax.BeginForm("Save", "Templates", new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "AddEditPlaceHolder",
OnSuccess = "OnSaveSuccess",
HttpMethod = "Post"
}))
{
<div>
<div id="AddEditPlaceHolder"></div>
<div id="PopupButtons" class="btn-holder-centered">
<input type="submit" value="Save" name="SaveButton" />
<input type="button" value="Cancel" name="SaveCancelButton" id="CancelEditHandler" />
</div>
</div>
}
</div>
here is form which I render in AddEditPlaceHolder via js:
#model TemplatesViewModel
<div class="form-field-plain overflow">
<div class="forRow narRow float-left">
#Html.LabelFor(x => x.Revocable)
#Html.CheckBoxFor(x => x.Revocable)
</div>
</div>
<div class="form-field-plain overflow">
<div class="forRow narRow float-left">
#Html.LabelFor(x => x.HtmlTemplate)
#Html.TextAreaFor(x => x.HtmlTemplate)
</div>
</div>
#Html.Partial("_VariablesGridView", Model.Variables)
_VariablesGridView.cshtml:
#model List<TemplateVariableViewModel>
<table id="TemplateVariablesGrid">
<thead>
<tr>
<td>Tag/Code</td>
<td>Prompt</td>
<td>Action</td>
</tr>
</thead>
<tbody>
#foreach (var i in Model)
{
<tr>
<td>
#Html.TextBox("txtTag", #i.Tag, new {})
</td>
<td>
#Html.TextBox("txtPrompt", #i.Prompt, new { })
</td>
<td>
#Html.HiddenFor(x => x.First(s => s.Id == #i.Id).Id)
<label class="delete-variable">delete</label>
</td>
</tr>
}
</tbody>
</table>
<br />
<input type="button" name="btnAddTemplateVariable" value="add new variable"/>
<br />
My problem is :
in Controller 'save form' method public ActionResult Save(TemplateViewModel model)
my model contains all data from form but TemplateViewModel.Variables is empty
Is there any way to fill it in there?
Models:
public class TemplateViewModel
{
public int Id { get; set; }
public string HtmlTemplate { get; set; }
public List<TemplateVariableViewModel> Variables { get; set; }
}
public class TemplateVariableViewModel
{
public int Id { get; set; }
public string Tag { get; set; }
public string Prompt { get; set; }
}
I believe it is because the ASP.Net MVC binding is not putting these fields in context, have a look at your field names delivered to the browser, what is txtTag prefixed by when it gets to the browser and what is is after you do the following:
#Html.Partial("_VariablesGridView", Model)
_VariablesGridView.cshtml:
#model TemplatesViewModel
...
#for (int i = 0; i < Model.Variables.Count; i++)
#Html.TextBox("txtTag", #Model.Variables[i].Tag, new {})
Forgive me if this fails miserably (again), I'm shooting from the hip.

How to call a method from the View? MVC

I have a View with a <input type="submit" value="Create" /> when a User click create the Action Method should be activated and the Result written in the db.
At the moment when a User click Create Button in the View nothing happen. Could you tell me what I'm doing wrong? thanks
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using TestGuestBook.Models;
using TestGuestBook.Models.Repositories;
using TestGuestBook.ViewModels;
namespace TestGuestBook.Controllers
{
[HandleError]
public class HomeController : Controller
{
ICommentRepository _repository;
public HomeController()
{
_repository = new CommentRepository();
}
// Dependency Injection enabled constructors
public HomeController(ICommentRepository repository)
{
_repository = repository;
}
public ActionResult Index()
{
// Get all Comments
List<Comment> commentItems = _repository.FindAll().ToList();
// Create the ViewModel and associate the list of comments
CommentListCreateViewModel viewModel = new CommentListCreateViewModel();
viewModel.CommentItems = commentItems;
return View(viewModel);
}
public ActionResult Create()
{
CommentListCreateViewModel createViewModel = new CommentListCreateViewModel();
return View(createViewModel);
}
[HttpPost]
public ActionResult Create(CommentListCreateViewModel createViewModel)
{
if (ModelState.IsValid)
{
Comment comment = new Comment
{
Nominative = createViewModel.Nominative,
Email = createViewModel.Email,
Content = createViewModel.Content
};
_repository.Add(comment);
_repository.Save();
}
return View();
}
}
}
View
#model TestGuestBook.ViewModels.CommentListCreateViewModel
#{
ViewBag.Title = "Index";
}
<h2>
Index</h2>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>ListAddCommentsViewModel</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Nominative)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Nominative)
#Html.ValidationMessageFor(model => model.Nominative)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Content)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Content)
#Html.ValidationMessageFor(model => model.Content)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<table>
<tr>
<th>
Nominative
</th>
<th>
Email
</th>
<th>
Content
</th>
<th>
</th>
</tr>
#foreach (var item in Model.CommentItems)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Nominative)
</td>
<td>
#Html.DisplayFor(modelItem => item.Email)
</td>
<td>
#Html.DisplayFor(modelItem => item.Content)
</td>
<td>
</td>
</tr>
}
</table>
You need to direct the form to your Create controller method:
#using (Html.BeginForm("Create", "Home"))
You can leave it as Html.BeginForm() and after the save, call return RedirectToAction("Index"); The added item should now show in the list. It was probably saving all along, it just wasn't being re-directed to the Index view afterwards.

MVC 3 - System.byte[] output instead of showing image

I complete index.cshtml file looks like this...
#model IEnumerable<MvcMyApplication.Models.SubProductCategory2>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#Html.ActionLink("Create New", "Create")
<p>
some javascripts code
</p>
<input type="text" name="search" id="search" style="color: #F5FFFA;
font-family: Constantia, Georgia, serif; font-weight: bold; font-size:
14px; background-color: #D2691E;" size="15" />
<table id="admin_table">
<thead>
<tr>
<th></th>
<th>
CategoryName
</th>
<th>
SubCategoryName
</th>
<th>
Picture
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model) {
<tr>
<td>
#Html.ActionLink("Edit", "Edit", new {
id=item.SubProductCategoryID }) |
#Html.ActionLink("Delete", "Delete", new {
id=item.SubProductCategoryID })
</td>
<td>
#item.ProductCategory.CategoryName
</td>
<td>
#item.SubCategoryName
</td>
<td>
<img alt="#Html.Encode(item.SubProductCategoryID)"
src='#(Url.Action(("Image")) + item.SubProductCategoryID)'
width="100" height="100" />
</td>
</tr>
}
Complelte Create.cshtml file looks this...
enter code here
#model MvcMyApplication.Models.ProCat1
#{
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", "ProductCategoryL2", FormMethod.Post,
new { enctype = "multipart/form-data"}))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>ProCat1</legend>
<div class="editor-label">
#Html.LabelFor(model => model.CategoryName)
</div>
<div class="editor-field">
#Html.DropDownList("ProductCategoryID",
(IEnumerable<SelectListItem>)ViewData["CategoryName"])
#Html.ValidationMessageFor(model => model.CategoryName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.SubCategoryName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.SubCategoryName)
#Html.ValidationMessageFor(model => model.SubCategoryName)
</div>
<!-- <div class="editor-field">
<img alt="Current image" src='#Url.Action("image", new { id =
Model.SubProductCategoryID } )' />
<input type="file" id="fileUpload" name="fileUpload" size="23"/>
#Html.ValidationMessageFor(model => model.SubProductCategoryID)
</div> -->
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Controller for Create and Image looks like this...
enter code here
public ActionResult Create()
{
PopulateProductCategoryDropDownList(-1);
return View();
}
private void PopulateProductCategoryDropDownList(object selectedCategory)
{
ViewBag.CategoryName = new SelectList ((from d in db.ProductCategories select d).ToList(),
"ProductCategoryID", "CategoryName", selectedCategory);
}
//
// POST: /ProductCategoryL2/Create
[HttpPost]
public ActionResult Create([Bind(Exclude = "SubProductCategoryID")] SubProductCategory2 Createsubcat2, FormCollection values)
{
if (ModelState.IsValid)
{
if (Request.Files.Count > 0)
{
Createsubcat2.Picture1 = (new FileHandler()).uploadedFileToByteArray((HttpPostedFileBase)Request.Files[0]);
}
db.AddToSubProductCategory2(Createsubcat2);
db.SaveChanges();
return RedirectToAction("/");
}
PopulateProductCategoryDropDownList(Createsubcat2.ProductCategoryID);
return View(Createsubcat2);
}
public FileResult Image(int id)
{
const string alternativePicturePath = #"/Content/question_mark.jpg";
SubProductCategory2 product = db.SubProductCategory2.Where(k => k.SubProductCategoryID == id).FirstOrDefault();
MemoryStream stream;
if (product != null && product.Picture1 != null)
{
stream = new MemoryStream(product.Picture1);
}
else // If product cannot be found or product doesn't have a picture
{
stream = new MemoryStream();
var path = Server.MapPath(alternativePicturePath);
var image = new System.Drawing.Bitmap(path);
image.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
stream.Seek(0, SeekOrigin.Begin);
}
return new FileStreamResult(stream, "image/jpeg");
}
FileHandler class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Drawing;
public class FileHandler
{
/// <summary>
/// Converts a HttpPostedFileBase into a byte array
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public byte[] uploadedFileToByteArray(HttpPostedFileBase file)
{
int nFileLen = file.ContentLength;
byte[] result = new byte[nFileLen];
file.InputStream.Read(result, 0, nFileLen);
return result;
}
}
}
Thanks tvanfosson.
Your URL is totally wrong; you want to call Url.Action with an action name and a parameter.
Your alt text is also wrong; you're effectively calling ToString() on a byte array, which returns "System.Byte[]".
Since your incorrectly generated URL doesn't exist, it's showing the incorrect alt text instead.
If Picture1 is image data, #Html.EditorFor(model => model.Picture1) isn't what you want. You probably want to call the Image action to display the picture inline.
...code sample coming
<div class="editor-field">
<img alt="Current image" src='#Url.Action("image", new { id = Model.PictureID } )' />
<input type="file" id="fileUpload" name="fileUpload" size="23"/>
#Html.ValidationMessageFor(model => model.PictureID)
</div>
Then change the create GET method so that it populates the PictureID instead of the Picture on the model.

Resources