The id is missed when form is posted to controller - c#

I am developing a mvc website.I have a table called member .this table has a controller and the controller has an edit method as you can see :
public ActionResult Edit()
{
int userId = _memberRepository.ReturnMemberIdByMobile(User.Identity.Name);
ViewBag.Edit = _memberRepository.FindById(userId).First();
return View();
}
[HttpPost]
public ActionResult Edit(Member value)
{
try
{
if (_memberRepository.Edit(value))
{
value.RegisteredDate = DateTime.Now;
_memberRepository.Save();
TempData["Success"] = "با موفقیت ویرایش شد ...";
string strLocation = HttpContext.Server.MapPath("~/Image/users");
if (value.ImgByte != null)
{
value.ImgByte.SaveAs(strLocation + #"\" + value.Id + ".jpg");
}
}
}
catch (Exception)
{
TempData["Error"] = "ویرایش نشد، لطفاً مجدداً تلاش نمایید";
}
return RedirectToAction("Edit");
}
The edit view is correctly work.the problem is when i post my view to edit controller .the id of member is changed to 0 it means it is missed.why ?and the value can't be edited.
#using DCL
#{
ViewBag.Title = "Edit";
Layout = "~/Areas/user/Views/Shared/_shared.cshtml";
Member membervalue = new Member();
membervalue = ViewBag.Edit;
}
#using (#Html.BeginForm("Edit", "User", FormMethod.Post,
new {id = "form", enctype = "multipart/form-data"}))
{
if (TempData["Error"] != null)
{
<div class="pad margin no-print">
<div class="callout callout-info" style="margin-bottom: 0 !important; background-color: #ea0000 !important; border-color: #d20000">
#TempData["Error"]
</div>
</div>
}
if (TempData["Information"] != null)
{
<div class="pad margin no-print">
<div class="callout callout-info" style="margin-bottom: 0 !important; background-color: orangered !important; border-color: red">
#TempData["Information"]
</div>
</div>
}
if (TempData["Success"] != null)
{
<div class="pad margin no-print">
<div class="callout callout-info" style="margin-bottom: 0 !important; background-color: #00A65A !important; border-color: #00925A">
#TempData["Success"]
</div>
</div>
}
<div class="row">
<!-- general form elements -->
<div class="col-xs-12">
<div class="box">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">حساب کاربری</h3>
</div>
<!-- /.box-header -->
<!-- form start -->
<div class="box-body">
<div class="col-lg-7">
<div class="input-group">
<label for="Name">نام</label>
<input class="form-control" id="Name" name="Name" type="text" value="#membervalue.Name">
</div>
<div class="input-group">
<label for="family">نام خانوادگی</label>
<input class="form-control" id="family" name="family" type="text" value="#membervalue.Family">
</div>
<div class="input-group">
<label for="mobile">موبایل</label>
<input class="form-control" id="mobile" name="mobile" type="text" value="#membervalue.Mobile">
</div>
<div class="input-group">
<label for="password">رمز عبور</label>
<input class="form-control" id="password" name="password" type="password" value="#membervalue.Password">
</div>
<div class="input-group">
<label for="Email">ایمیل</label>
<input class="form-control" id="Email" name="Email" type="text" value="#membervalue.Email">
</div>
<div class="form-group">
<label for="ImgByte">عکس </label>
<input id="ImgByte" name="ImgByte" type="file">
</div>
<input type="hidden" id="Id" name="id" value="#membervalue.Id">
</div>
</div>
<!-- /.box-body -->
</div>
</div>
</div>
<!-- /.box -->
</div>
<div class="row" style="margin: 0; margin-bottom: 20px">
<div class="box-footer" style="direction: ltr">
<button type="submit" class="btn btn-info">ویرایش</button>
<a class="btn btn-gray" href="#Url.Action("Index", "Home", null)">انصراف</a>
</div>
</div>
}

Instead of using the viewbag for your model you should pass in the model as a strongly typed object. You can do this with the following change in the Action. Then in your view define the model at the top and you can use it throughout the code.
You will also need a #Html.HiddenFor tag for your id. Now it is no longer possible (without a compile time exception that is) to create a type-o. On your previous code maybe you cased Id incorrectly which would cause it not to be populated OR maybe the form field name was not cased correctly. This takes all those manual errors out of the equation.
public ActionResult Edit()
{
int userId = _memberRepository.ReturnMemberIdByMobile(User.Identity.Name);
var model = _memberRepository.FindById(userId).First();
return View(model); // pass this in as the model, do not use viewbag
}
View
#model = Member #* namespace qualified type *#
#*... editor code *#
#Html.HiddenFor(x => x.Id)
#Html.TextboxFor(x => x.Name) #* do this instead of manual input *#

I ran your code, and there is no mistake in it. Id is passed correctly to Edit (post) action. The only reason it can be empty in the code that you show is that FindById returned entity without Id property set.

Related

Data annotation validation happening on page load in ASP.Net Core

I am facing the issue of data validation being executed on load of a new page even though it is clearly coming from a Get method. Is there something that's triggering the validations on page load?
I have a button on a view to add a new Student record in the new screen :
View :
<a type="button" id="btnAddStudent" href='#Url.Action("Details","Student")' class="btn btn-tertiary" title="Add Student">Add Student</a>
The controller code for the Details action method in Student Controller is as follows.
[HttpGet]
public ActionResult Details(StudentInfo model)
{
//This is populating the model parameters as expected.
helper.StudentInfo(ref model);
return View(model);
}
The view for the Details screen is as follows. The page loads but is throwing validation errors even though it's a Get method.
<form id="frmSubmit" asp-action="Details" asp-controller="Student" method="post">
<input type="hidden" asp-for="StudentId" />
<div class="row">
<div class="col-xs-12">
#Html.ValidationSummary("", new { #class = "alert alert-danger validation" })
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label asp-for="Name">*StudentName</label><br />
<input asp-for="Name" class="form-control" maxlength="100" placeholder="Enter student name..." />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label asp-for="AddressLine1"></label><br />
<input asp-for="AddressLine1" class="form-control" placeholder="Enter address..." />
<span asp-validation-for="AddressLine1" class="text-danger"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label asp-for="AddressLine2"></label><br />
<input asp-for="AddressLine2" class="form-control" maxlength="100" />
<span asp-validation-for="AddressLine2" class="text-danger"></span>
</div>
</div>
</div>
<div class="box">
<div class="form-group pull-right">
<button type="submit" class="btn btn-primary" value="save"> Save</button>
</div>
</div>
Is there something I am doing wrong? I have verified that the debug control goes to the Get method.There's alos no on load scripts which are doing any sort of validation.
1.Your get method contains the model parameter, when the request hit the method it will judge the ModelState by default. And when you hit the get method by your shared <a>, it send request without any data, so the ModelState is invalid.
2.Default Tag helper displays ModelState's value not Model.
In conclusion, you will render the ModelState error although it is a get method.
Two ways you can resolve this problem. The first way is that you can add ModelState.Clear() before you return View:
public ActionResult Details(StudentInfo model)
{
ModelState.Clear(); //add this....
helper.StudentInfo(ref model);
return View(model);
}
The second way is do not add the model as parameter:
public ActionResult Details()
{
var model = new StudentInfo();
helper.StudentInfo(ref model);
return View(model);
}

Unable to bind data to the razor view even though the model is not null

Even though the model is not null the required html is not rendered. This is my razor view:
#model List<Product>
#{
ViewBag.Title = "Cart";
}
#for(int i=0;i<=Model.Count()-1;i++)
{
<p>foreach triggered</p>
var image = "~/images/" + Model[i].product_image_path;
<div class="row">
<div class="col">
<div class="row">
<div class="col-md-2">
<img src="#image" alt="No image" class="img-fluid" width="60" asp-append-version="true" />
</div>
<div class="col-md-4">
<div class="row">
<div class="col">
<p class="justify-content-md-start">#Model[i].ProductName</p>
</div>
</div>
<div class="row">
<div class="col">
<p>₹#Model[i].Price</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="row">
<div class="col-md-8">
#*change quantity button*#
<div class="input-group">
<button type="submit" class="btn btn-light"> - </button>
<input type="text" class="form-control" value="#Model[i].Quantity" readonly />
<button type="submit" class="btn btn-light"> + </button>
</div>
</div>
</div>
<br />
</div>
<div class="col-md-2">
<div class="row">
<div class="col">
<button class="btn btn-danger" type="button" id="button-minus">Remove</button>
</div>
</div>
</div>
</div>
</div>
</div>
}
Here is my get action method. This is basically retrieving the product from the models. I am returning an object of List<Product>. Trying to loop over it using for loop on razor view does not seem to work.
[HttpGet]
public IActionResult Cart()
{
var model = new CartProductViewModel();
var sessionId = HttpContext.Session.Id;
var allCartItems = context.cartItems;
var allProducts = context.products;
var currentCartItem = allCartItems.Where(p => p.Product.ProductId.Equals(sessionId)).Select(p=>p).ToList();
List<Product> products = new List<Product>();
foreach (var item in currentCartItem)
{
var id = item.Product.ProductId;
if (id is null) { return View("NotFound"); }
Product prod = allProducts.Where(p => p.ProductId.Equals(id)).Select(p=>p).Single();
products.Add(prod);
}
return View(products);
}

Returning error message using SweetAlert

In AccountController, I notice that the sample registration code catches UserFriendlyException and returns the error message in the ViewBag.
How can I return it from a SweetAlert?
[HttpPost]
public virtual async Task<ActionResult> Register(RegisterViewModel model)
{
try
{
// Code omitted for brevity
}
catch (UserFriendlyException ex)
{
ViewBag.ErrorMessage = ex.Message; // I need to return this using SweetAlert
return View("Register", model);
}
}
html code
<form action="javascript:;" id="register-form" class="login-form" method="post">
<div class="alert alert-danger display-hide">
<button class="close" data-close="alert"></button>
<span>Enter required fields. </span>
</div>
#if (#ViewBag.ErrorMessage != null)
{
<div class="alert alert-danger">
<i class="fa fa-warning"></i> #ViewBag.ErrorMessage
</div>
<script>abp.message.error("#ViewBag.ErrorMessage");</script>
<input type="hidden" value=" #ViewBag.ErrorMessage" id="hf_error" >
}
<div class="row">
<div class="col-xs-12">
<input type="text" class="form-control form-control-solid placeholder-no-fix form-group" autocomplete="off" name="name" placeholder="#L("Name")" required autofocus id="name">
</div>
<div class="col-xs-12">
<input class="form-control form-control-solid placeholder-no-fix form-group" type="text" autocomplete="off" placeholder="#L("Surname")" name="surname" required id="surname" />
</div>
<div class="col-xs-12">
<input type="password" class="form-control form-control-solid placeholder-no-fix form-group" autocomplete="off" name="password" placeholder="#L("Password")" required autofocus id="password">
</div>
</div>
<div class="row">
<div class="col-sm-6 text-left">
<div class="forgot-password" style="margin-top: 5px;">
Login To Your Account
</div>
</div>
<div class="col-sm-6 text-right">
<button class="btn green" id="btnSubmit" type="submit">Register</button>
</div>
<hr />
</div>
</form>
jquery function below
var jsonObject = {
Name: name,
Surname: surname,
//EmailAddress: email,
// UserName: username,
Password: password
};
abp.ajax({
url: abp.appPath + 'Account/Register',
type: 'POST',
data: JSON.stringify(jsonObject)
}).done(function(data) {
alert("done");
}).fail(function(data) {
alert("fail");
});
Since that method returns a View result, it makes sense to use ViewBag for the error message.
To show a SweetAlert, add the following in #section Scripts in Register.cshtml:
#section Scripts {
// ...
#if (ViewBag.ErrorMessage != null)
{
<script>abp.message.error("#ViewBag.ErrorMessage");</script>
/*<script>swal("#ViewBag.ErrorMessage", "", "error");</script>*/
}
}
Both <script> tags trigger identical popups.

Request is not receiving file - Asp.Net Mvc

I'm trying upload a file from my page, but the request is not receiving posted file.
My form is into a normal Bootstrap modal, and this is the view.
#model InventarioWeb.Mvc.ViewModels.InventarioViewModel
<!-- Modal -->
<div id="ImportadorModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Importar Arquivo</h4>
</div>
<div class="modal-body">
#using (Html.BeginForm("ImportarItensInventario", "Inventario", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="row">
<div class="col-md-10">
#*<h4>Input Groups</h4>*#
<div class="input-group">
<span class="input-group-btn">
<span class="btn btn-primary btn-file">
Procurar…
<input type="file"
id="fileToUpload"
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet">
</span>
</span>
<input type="text" class="form-control" readonly>
</div>
<span class="help-block">
Selecione um arquivo
</span>
</div>
<div class="col-md-10">
<input type="submit" id="SubmitArquivoInventario" name="Submit" value="Salvar Arquivo" class="btn btn-primary" disabled="disabled"/>
</div>
</div>
#*#Html.HiddenFor(x => x.InventarioId)*#
}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
And this is the controller's method
[HttpPost]
public ActionResult ImportarItensInventario(Guid inventarioId)
{
if (Request.Files["UploadInventarioItems"] == null || Request.Files["UploadInventarioItems"].ContentLength == 0)
{
return RedirectToAction(nameof(Details), new { id = inventarioId });
}
string path = $"{Server.MapPath("~/Uploads")}/{Request.Files["UploadInventarioItems"].FileName}";
if (System.IO.File.Exists(path))
{
System.IO.File.Delete(path);
}
Request.Files["UploadInventarioItems"].SaveAs(path);
var model = new InventarioViewModel {InventarioId = inventarioId};
var result = _arquivoAppService.ImportarArquivo(InventarioViewModel.ToModel(model), Request.Files["UploadInventarioItems"].FileName);
return RedirectToAction(nameof(Details), new { id = inventarioId});
}
When I request, the id parameter is received, but my file isn't.
Besides, the Request.Files does not have any item.
What I'm doing wrong??
Add name attribute to your input type file, you can workaround to get the file without this attribute, but it's more convenient.
<input type="file" id="fileToUpload" name="upload" accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet">
and use in server this method to get the file:
if (Request.Files["upload"] == null || Request.Files["upload"].HasFile())
{
//do something
}
or like this for multiple files:
foreach (string inputTagName in Request.Files)
{
if (!Request.Files[inputTagName ].HasFile()) continue;
//... continue processing
}

How to use 2 buttons on the same asp.net mvc form

In my asp.net mvc form I have 2 buttons, one to save which will save data from the from in a list in sharepoint and the second button does the same and additionally it applies some css colors.
I doubt however how to use 2 actions on the same form (same controller)
this is my view
#{
Layout = "~/Views/Shared/_LayoutPage2.cshtml";
}
#using (Html.BeginForm("Index", "Movies", FormMethod.Post))
{
<div class="row">
<div class="col-md-8">
<div class="col-xs-6 col-sm-3" id="stylesheet">Hojas de estilos</div>
<div class="col-xs-6 col-sm-3">
#Html.DropDownList("cssFiles", (IEnumerable<SelectListItem>)ViewBag.cssFiles, "Crear Nuevo", new { #class = "form-control", #id = "selCssFile" })
<span>
<input type="text" class="form-control" id="txtFileName" style="display:none;" placeholder="Nombre del archivo">
</span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8">
Color base, links, botones, borde encabezado y pie
</div>
<div class="col-md-4">
<div id="colorSelector" class="colorSelector"><div style="background-color: #0000ff"></div></div>
</div>
</div>
<div class="row">
<div class="col-md-8">
Fondo de la pagina, fondo de los cuadros
</div>
<div class="col-md-4">
<div id="colorSelector2" class="colorSelector"><div style="background-color: #0000ff"></div></div>
</div>
</div>
<div class="row">
<div class="col-md-8">
Navegación
</div>
<div class="col-md-4">
<div id="colorSelector3" class="colorSelector"><div style="background-color: #0000ff"></div></div>
</div>
</div>
<div class="row">
<div class="col-md-8">
Navegación (Item seleccionado)
</div>
<div class="col-md-4">
<div id="colorSelector4" class="colorSelector"><div style="background-color: #0000ff"></div></div>
</div>
</div>
<div class="row">
<div class="col-md-8">
Pie de página
</div>
<div class="col-md-4">
<div id="colorSelector5" class="colorSelector"><div style="background-color: #0000ff"></div></div>
</div>
</div>
<div class="row" id="buttons">
<div class="col-md-8">
</div>
<div class="col-md-4">
<button type="button" class="btn btn-success">Guardar</button>
<button type="button" class="btn btn-primary">Guardar y aplicar</button>
</div>
</div>
}
My index action on the customize controller so far
public class CustomizeController : Controller
{
// GET: Customize
public ActionResult Index()
{
User spUser = null;
var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext);
using (var cc = spContext.CreateUserClientContextForSPHost())
{
int aprovisionado = (int)cc.Web.GetPropertyBagValueInt("Vinculosc.PlantillasIntranet.Aprovisionado", 0);
if (aprovisionado == 0)
{
string libraryName = "ConfiguraciónColores";
Dictionary<string, string> fields = new Dictionary<string, string>();
fields.Add("Color1", "Text");
fields.Add("Color2", "Text");
fields.Add("Color3", "Text");
fields.Add("Color4", "Text");
fields.Add("Color5", "Text");
//ProvisionTemplate(cc);
CreateLibrary(cc, libraryName);
AddFields(cc, libraryName, fields);
}
}
#region comments
/*Uri hostWeb = new Uri(Request.QueryString["SPHostURL"]);
using (var clientContext = TokenHelper.GetS2SClientContextWithWindowsIdentity(hostWeb, Request.LogonUserIdentity))
{
var web = clientContext.Web;
clientContext.Load(web, w => w.Lists.Include(l => l.Title).Where(l => !l.hidden));
clientContext.ExecuteQuery();
return View(web.Lists);
}*/
#endregion
return View();
}
You can put the same name in the view with different value
<button type="submit" name="Guardar" value="guardar" class="btn btn-success">Guardar</button>
<button type="submit" name="Guardar" value="aplicar" class="btn btn-primary">Guardar y aplicar</button>
And in the Controller you can check the value of the button
if (Request["Guardar"].ToString() == "guardar")
{
//Your code for the first button
}
else
{
//Your code for the second button
}
Your button type should be "submit", and you can give them a name... Same name, that can be reused in a model, or by Request.Form["GiveAName"]
Your controller should have a
[HttpPost]
public ActionResult Index()
{
... Your code to retrieve form values
}
Anyway that's bad coding... You should work with models to inject on the view, that same model could be retrieved back and so you don't have to worry about retrieving form values. :=)

Categories

Resources