I have a program with login and logout.
I have an exercise class, I have a create view that allows me to create exercises that are composed by name, photo, video.
I fill the form in View Create and when I click create this error appears to me
NullReferenceException: Object reference not set to an instance of an object.
WebApplication1.Controllers.ExerciciosGinasiosController.Create(ExerciciosGinasio exerciciosGinasio, IFormFile fotografia, IFormFile video) in ExerciciosGinasiosController.cs
string nome_ficheiro = Path.GetFileName(fotografia.FileName);
In the exercise class I have
[Table("Exercicios_Ginasio")]
public partial class ExerciciosGinasio
{
public ExerciciosGinasio()
{
Inclui = new HashSet<Inclui>();
}
[Key]
[Column("IDExercicios_Ginasio")]
public int IdexerciciosGinasio { get; set; }
[Required]
[Column("nome")]
[StringLength(30)]
public string Nome { get; set; }
[Required]
[Column("texto_descritivo")]
[StringLength(1000)]
public string TextoDescritivo { get; set; }
[Required]
[Column("foto")]
public string Foto { get; set; }
[Required]
[Column("video")]
public string Video { get; set; }
[InverseProperty("IdexerciciosGinasioNavigation")]
public virtual ICollection<Inclui> Inclui { get; set; }
}
}
In the controller belonging to the Exercises class (ExercisesController) I have this method in order to create a new exercise
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("IdexerciciosGinasio,Nome,TextoDescritivo,Foto,Video")] ExerciciosGinasio exerciciosGinasio, IFormFile fotografia,IFormFile video)
{
string caminho = Path.Combine(_hostEnviroment.ContentRootPath, "wwwroot\\Exercicios");
string nome_ficheiro = Path.GetFileName(fotografia.FileName);
string caminho_completo = Path.Combine(caminho, nome_ficheiro);
FileStream fs = new FileStream(caminho_completo, FileMode.Create);
fotografia.CopyTo(fs);
exerciciosGinasio.Foto = caminho_completo;
fs.Close();
string caminho2 = Path.Combine(_hostEnviroment.ContentRootPath, "wwwroot\\Exercicios");
string nome_ficheiro2 = Path.GetFileName(video.FileName);
string caminho_completo2 = Path.Combine(caminho2, nome_ficheiro2);
FileStream _fs = new FileStream(caminho_completo2, FileMode.Create);
video.CopyTo(_fs);
exerciciosGinasio.Video = caminho_completo2;
_fs.Close();
if (ModelState.IsValid)
{
_context.Add(exerciciosGinasio);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(exerciciosGinasio);
}
And in the view of this method I have
#model WebApplication1.Models.ExerciciosGinasio
#{
ViewData["Title"] = "Create";
}
<h4>Criar Exercicio</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Nome" class="control-label"></label>
<input asp-for="Nome" class="form-control" />
<span asp-validation-for="Nome" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="TextoDescritivo" class="control-label"></label>
<input asp-for="TextoDescritivo" type="text" class="form-control" />
<span asp-validation-for="TextoDescritivo" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Foto" class="control-label"></label>
<input asp-for="Foto" type="file" class="form-control" accept=".png, .jpg, .bmp" value="" />
#*<span asp-validation-for="Foto" class="text-danger"></span>*#
<div>
<input type="hidden" name="fotografia" value="0" />
</div>
<div class="form-group">
<label asp-for="Video" class="control-label"></label>
<input asp-for="Video" type="file" class="form-control" />
#*<span asp-validation-for="Video" class="text-danger"></span>*#
</div>
<div>
<input type="hidden" name="video" value="0" />
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<br />
<div>
<a asp-action="Index" asp-controller="Home">Voltar</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Does anyone know what may be causing this error? And how can I solve
NullReferenceException: Object reference not set to an instance of an object.
string nome_ficheiro = Path.GetFileName(fotografia.FileName);
In your View page, we can find you are using hidden field(s) with default value 0 for fotografia and video, but your Create action expects file via IFormFile object, if you debug your code, you would find fotografia is null, which would casue exception while you read FileName property of fotografia.
To fix it, you can modify the code like below.
Inputs of Photo and Video
<div class="form-group">
<label asp-for="Foto" class="control-label"></label>
<input type="file" class="form-control" name="fotografia" accept=".png, .jpg, .bmp" />
</div>
<div>
<input type="hidden" name="Foto" value="0" />
</div>
<div class="form-group">
<label asp-for="Video" class="control-label"></label>
<input type="file" name="fvideo" class="form-control" />
</div>
<div>
<input type="hidden" name="Video" value="0" />
</div>
Controller Action
[HttpPost]
public IActionResult Create([Bind("IdexerciciosGinasio,Nome,TextoDescritivo,Foto,Video")] ExerciciosGinasio exerciciosGinasio,
IFormFile fotografia,
IFormFile fvideo)
{
string nome_ficheiro = Path.GetFileName(fotografia.FileName);
//code logic here
return View(exerciciosGinasio);
}
Test Result
Related
I have a small project where I am trying to add to the database. I get a null reference exception but I think the issue is that the model binding does not work properly.
Here is the razor :
<form method="post" class="col-sm-12" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<div class="col-sm-12">
<label>Name</label>
<span></span>
</div>
<div class="col-sm-12">
<input class="col" asp-for="Product.Name" />
<span asp-validation-for="Product.Name" class="text-danger"></span>
</div>
<div class="col-sm-12">
<label>Description</label>
</div>
<div class="col-sm-12">
<textarea cols="60" rows="5" asp-for="#Model.Product.Description"></textarea>
<span asp-validation-for="Product.Description" class="text-danger"></span>
</div>
<div class="col-sm-12 ">
<label>Image</label>
</div>
<div class="col-sm-12">
<input type="file" asp-for="Image" />
<span asp-validation-for="Image" class="text-danger"></span>
</div>
<div class="col-sm-12">
<label>Categories</label>
</div>
<select name="categorycombo" asp-for="Product.CategoryId">
<option value="">Choose Category</option>
#foreach (var category in #Model.Categories)
{
<option value="#category.Id.ToString()">#category.Name.ToString()</option>
}
</select>
<div class="col-sm-12 ">
<input type="submit" value="Add" />
</div>
</div>
</form>
And here is the OnPost method :
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return await GetPage();
}
var path = Path.Combine(_webHostEnvironment.WebRootPath, "Images/Products");
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
if (Image.Length > 0)
{
var fileStream = new FileStream(Path.Combine(path, Image.FileName), FileMode.Create);
***Product.ImageUrl = Path.Combine("Images/Products", Image.FileName);***
await Image.CopyToAsync(fileStream);
}
await _productRepo.Add(Product);
return RedirectToPage("./AddProduct");
}
on the line where I create the ImageUrl I get NullReference exception for product, and it should not be null if the binding is working properly. At the same time maybe there is something I can't see.
I forgot to add the code that does the model binding here it is :
[BindProperty]
public IEnumerable<ProductViewModel> Products { get; private set; }
[BindProperty]
public IEnumerable<CategoryViewModel> Categories { get; private set; }
[BindProperty]
public ProductViewModel Product { get; private set; }
[Required]
[BindProperty]
public IFormFile Image { get; set; }
Solved :
How ?
Simple, though I don't understand exactly why.
[BindProperty]
public ProductViewModel Product { get; private set; }
in the previous snippet we remove the private set; and replace it with set; and it works.
the reasoning I don't understand because I have the same code for a different class and that works, and the only difference between the two is that the other class does don have and IForm File in the form.
Online I found some bits of info that say that the code that does model binding is not part of the page model so adding private or internal to the property setter will prevent it from being set by the model binder.
I don't know what I am talking about but it seems like it fixed it.
I have a class that includes one dictionary<int,string>.
int is the key of radio button and value is the choice title.
I'm trying to get a list of dictionaries in controller includes keys and values of radio buttons.
when I run the program the list is 0. I think there is something wrong with the name of the radio buttons and input for choice title but I don't know what should I write.
public class ChoiceQuestion
{
public int QuestionId { get; set; }
public Dictionary<int, string> Choice { get; set; }
public int Answer { get; set; }
}
in the controller I have this:
public IActionResult CreateQuestion(int courseId, List<ChoiceQuestion> choices,
QuestionType type, Question question)
{
_questionService.AddQuestion(courseId, type, choices, question);
return RedirectToAction("Index");
}
and this is my view:
<div class="form-group choiceDiv" style="display: none;" id="choiceDiv">
<a id="plus"><i class="glyphicon glyphicon-plus"></i></a>
<input type="radio" name="choices.choice[0].key" value="1" />
<input type="text" placeholder="گزینه " name="choices.choice[0].value" />
<input type="radio" name="choices.choice[1].key" value="1" />
<input type="text" placeholder="گزینه " name="choices.choice[1].value" />
<span asp-validation-for="Choice" class="text-danger"></span>
</div>
Firstly you want to pass data to List<ChoiceQuestion> choices,so your name of input need to be choices[xxx].choice[xxx].
And then,you can change your text type inputs name before form submitting,so that text type inputs' value will be binded to dictionary of List<ChoiceQuestion> choices.
Here is a working demo:
<form method="post" id="myform">
<div class="form-group choiceDiv" style="display: none;" id="choiceDiv">
<a id="plus"><i class="glyphicon glyphicon-plus"></i></a>
<input type="radio" name="choices[0].choice[0].key" value="1" />
<input type="text" placeholder="گزینه " name="choices[0].choice[key]" value="choicetitle1" />
<input type="radio" name="choices[0].choice[1].key" value="2" />
<input type="text" placeholder="گزینه " name="choices[0].choice[key]" value="choicetitle2" />
<span asp-validation-for="Choice" class="text-danger"></span>
</div>
<input type="submit" value="submit" />
</form>
<script>
$('#myform').submit(function () {
var keys = [];
var count = 0;
$("#choiceDiv input[type='radio']").each(function () {
keys.push($(this).val());
});
$("#choiceDiv input[type='text']").each(function () {
$(this).attr("name", $(this).attr("name").replace("key", keys[count]));
count++;
});
});
</script>
I change text type input names to choices[0].choice[key],and before form submitting,I replace 'key' in name to the value of radio button.And then form will post dictionary data.
result:
Or you can remove radio buttons,and use view like the following:
<div class="form-group choiceDiv" style="display: none;" id="choiceDiv">
<a id="plus"><i class="glyphicon glyphicon-plus"></i></a>
<input type="text" placeholder="گزینه " name="choices[0].choice[1]" value="choicetitle1"/>
<input type="text" placeholder="گزینه " name="choices[0].choice[2]" value="choicetitle2"/>
<span asp-validation-for="Choice" class="text-danger"></span>
</div>
And then you will get key=1,value="choicetitle1";key=2,value="choicetitle2" in dictionary.
I have an exercise class and a view that allows me to create exercises.
One of the variables is a video, how can you insert a video in order to save it in the database and present it in the view?
In exercise class I have
[Table("Exercicios_Ginasio")]
public partial class ExerciciosGinasio
{
public ExerciciosGinasio()
{
Inclui = new HashSet<Inclui>();
}
[Key]
[Column("IDExercicios_Ginasio")]
public int IdexerciciosGinasio { get; set; }
[Required]
[Column("nome")]
[StringLength(30)]
public string Nome { get; set; }
[Required]
[Column("texto_descritivo")]
[StringLength(1000)]
public string TextoDescritivo { get; set; }
[Required]
[Column("foto")]
public string Foto { get; set; }
[Required]
[Column("video")]
public string Video { get; set; }
[InverseProperty("IdexerciciosGinasioNavigation")]
public virtual ICollection<Inclui> Inclui { get; set; }
}
}
In the controller Exercises I used the function Create automatically generated in the creation of the controller
In the method I added code to save the image in the database
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("IdexerciciosGinasio,Nome,TextoDescritivo,Foto,Video")] ExerciciosGinasio exerciciosGinasio, IFormFile fotografia,IFormFile video)
{
string caminho = Path.Combine(_hostEnviroment.ContentRootPath, "wwwroot\\Exercicios");
string nome_ficheiro = Path.GetFileName(fotografia.FileName);
string caminho_completo = Path.Combine(caminho, nome_ficheiro);
FileStream fs = new FileStream(caminho_completo, FileMode.Create);
fotografia.CopyTo(fs);
exerciciosGinasio.Foto = caminho_completo;
fs.Close();
string caminho2 = Path.Combine(_hostEnviroment.ContentRootPath, "wwwroot\\Exercicios");
string nome_ficheiro2 = Path.GetFileName(video.FileName);
string caminho_completo2 = Path.Combine(caminho2, nome_ficheiro2);
FileStream _fs = new FileStream(caminho_completo2, FileMode.Create);
video.CopyTo(_fs);
exerciciosGinasio.Video = caminho_completo2;
_fs.Close();
if (ModelState.IsValid)
{
_context.Add(exerciciosGinasio);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(exerciciosGinasio);
}
So how do I put it in the view to insert a video and save it in the database?
In order to be able to present it in the index
#model WebApplication1.Models.ExerciciosGinasio
#{
ViewData["Title"] = "Create";
}
<h4>Criar Exercicio</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Nome" class="control-label"></label>
<input asp-for="Nome" class="form-control" />
<span asp-validation-for="Nome" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="TextoDescritivo" class="control-label"></label>
<input asp-for="TextoDescritivo" type="text" class="form-control" />
<span asp-validation-for="TextoDescritivo" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Foto" class="control-label"></label>
<input asp-for="Foto" type="file" class="form-control" accept=".png, .jpg, .bmp" value="" />
#*<span asp-validation-for="Foto" class="text-danger"></span>*#
<div>
<input type="hidden" name="fotografia" value="0" />
</div>
<div class="form-group">
<label asp-for="Video" class="control-label"></label>
<input asp-for="Video" type="file" class="form-control" />
#*<span asp-validation-for="Video" class="text-danger"></span>*#
</div>
<div>
<input type="hidden" name="video" value="0" />
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<br />
<br />
<br />
<br />
<div>
<a asp-action="Index" asp-controller="Home">Voltar</a>
</div>
<br />
<br />
<br />
<br />
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
I tested it this way, and I got this error
NullReferenceException: Object reference not set to an instance of an object.
WebApplication1.Controllers.ExerciciosGinasiosController.Create(ExerciciosGinasio exerciciosGinasio, IFormFile fotografia, IFormFile video) in ExerciciosGinasiosController.cs, line 64
WebApplication1.Controllers.ExerciciosGinasiosController.Create(ExerciciosGinasio exerciciosGinasio, IFormFile fotografia, IFormFile video) in ExerciciosGinasiosController.cs
string nome_ficheiro = Path.GetFileName(fotografia.FileName);
Can someone help me solve it?
I have a page Item Edit with multiple partial rendered forms for images delete. Item Edit page:
#model EditModel
<form method="post" enctype="multipart/form-data">
<input asp-for="ItemModel.Id" type="hidden" />
<input asp-for="ItemModel.AllOtherFields" type="hidden" />
</form>
#if (Model.ItemModel.ImageViewModels != null && Model.ItemModel.ImageViewModels.Any())
{
foreach(var imageViewModel in Model.ItemModel.ImageViewModels)
{
Html.RenderPartial("ItemImage/_itemImageEdit", imageViewModel);
}
}
ItemImage/_itemImageEdit
#model ViewModels.ItemImageViewModel
<form asp-controller="Images" asp-action="Delete" method="post">
<input type="hidden" asp-for="#Model.Id" />
<img src="#Url.Action("Get", "Images", new { id = Model.Id })" />
<input type="submit" value="Delete" />
</form>
and here is my strange final html
<form method="post" action="/Images/Delete/5" novalidate="novalidate">
<input type="hidden" data-val="true" data-val-required="The Id field is required." id="Id" name="Id" value="5">
<img src="/Images/Get/10">
<input type="submit" value="Delete">
</form>
Where 5- Item id and 10 - image Id. So this is expected and correct
<img src="/Images/Get/10">
while this is not. Item Id used instead of id (ItemImageViewModel.id)
action="/Images/Delete/5"
I have no idea why does #Model.Idgenerate different ids on the same subview.
Edit1:
public class ItemImageViewModel
{
[BindProperty]
public int Id { get; set; }
public string Title { get; set; }
public int ItemId { get; set; }
}
public class ItemViewModel
{
public ItemViewModel()
{
}
public ItemViewModel(ItemViewModel vm)
{
Id = vm.Id;
Title = vm.Title;
ImageViewModels = vm.ImageViewModels;
}
public int Id { get; set; }
public string Title { get; set; }
public IEnumerable<ItemImageViewModel> ImageViewModels { get; set; }
}
I have removed unrelated fields.
Debugger shows alright
Now this weird piece of code generates what it supposed to generate
<form action="#Url.Action("Delete", "Images", new { id = Model.Id })" method="post">
<input type="hidden" id="Id" name="Id" value="#Html.DisplayFor(m => Model.Id)" />
#Html.HiddenFor(m => Model.ItemId)"
<img src="#Url.Action("Get", "Images", new { id = Model.Id })" />
<input type="text" asp-for="#Model.Title" />
<input type="submit" value="Delete" />
</form>
<form action="/Images/Delete/10" method="post" novalidate="novalidate">
<input type="hidden" id="Id" name="Id" value="10">
<input data-val="true" data-val-required="The ItemId field is required." id="ItemId" name="ItemId" type="hidden" value="5">"
<img src="/Images/Get/10">
<input type="text" id="Title" name="Title" value="Jacket">
<input type="submit" value="Delete">
</form>
I have a form with all fields, less one of it, filled from user. This is the class passed through the form
public class CarForm {
private String id;
private Integer initialKm;
private String carChassis;
private String note;
private String carType;
private Integer fleet;
The only one field, fleet, I would like to set before pass the form, or better, set it from HTML. For example:
<div class="form-group">
<label>Fleet application</label> <input type="text"
class="form-control" th:field="*{fleet}"
th:placeholder="${fleetApplication}" readonly="readonly">
</div>
So I would like to show ${fleetApplication.application} and set into fleet this value, or, if it is possible, set another value${fleetApplication.idFleet}.
Is it possible one of these solutions?Thanks
Update: as suggested by #Faraj Farook I resolved so:
<div class="form-group">
<label>Fleet application</label>
<!-- Show fleet application -->
<input class="form-control" type="text" th:value="${fleetApplication.application}" readonly="readonly" />
<!-- Save into fleet the value of idFleet -->
<input type="hidden" name="fleet" th:value="${fleetApplication.idFleet}" />
</div>
Setting it in the server side
controller
String action(Model model){
CarForm carForm = new CarForm();
carForm.setFleet(<some value>);
model.addAttribute("obj", carForm);
return view.html;
}
view.html
<div class="form-group">
<label>Fleet application</label>
<input type="text" th:field="*{fleet}" readonly/>
</div>
setting it in the client side
view.html
<div class="form-group">
<label>Fleet application</label>
<input type="text" readonly th:value="${someValueVariable}"/>
<input type="hidden" name="fleet" th:value="${someValueVariable}"/>
</div>