How to add alert class in viewbag from controller - asp.net-mvc

Here i am trying to add bootstrap alert class to the exception shown in ViewBag.message from controller on clicking the create button. But adding the class shows the exception 'string' does not contain a definition for 'cssClass'.
Below Is Create.cshtml
#model WebApplication8.Models.Info
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
<div class="errormsg">
#ViewBag.message
</div>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Info</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">
#Html.LabelFor(model => model.des, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.des, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.des, "", new { #class = "text-danger" })
</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>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Below is Create Action Method In controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "id,name,des")] Info info)
{
try
{
if (ModelState.IsValid)
{
db.create(info);
return RedirectToAction("Index");
}
}
catch (Exception ex)
{
ViewBag.message = ex.Message;
ViewBag.message.cssClass = "alert alert-danger";
return View(info);
}
return View(info);
}
below is Interface Implementer class
public class StudentInfo : IStudentInfo
{
private AbcdEntities db1 = new AbcdEntities();
public void create(Info info)
{
if (info.name!=null)
{
if (info.des!=null)
{
db1.Infoes.Add(info);
db1.SaveChanges();
}
else
{
throw new Exception("Des Cannot Be Empty");
}
}
else
{
throw new Exception("Name Cannot Be Empty");
}
}

ViewBag.message = ex.Message;
You assign to the ViewBag a property message passing to it the Exception.Message, a simple string.
ViewBag.message.cssClass = "alert alert-danger";
Then you try to access a non existent property of a string.
I think you need to understand better the usage of the viewBag, of dynamics, and in wich way MVC propose his way to work on views with Razor.
If you want a complex object in the viewBag you need to create something similar with a dynamic:
ViewBag.Message = new { Text= ex.Message, CssClass = "alert alert-danger" }
and then use it in this way:
<div class="errormsg #ViewBag.Message.CssClass">
#ViewBag.Message.Text
</div>
If it is a recurrent way to represent a return message in a view, you can create a viewModel class to represent the message and create an helper in Razor to enclosure this render rules in a single place.

I've done the following to do what you're looking for using Tempdata.
#*Display any messages returned from other views*#
<div>
#*Error Message*#
#if (TempData["error"] != null)
{
<div class="alert alert-danger">#TempData["error"]</div>
}
</div>
You will need to check your Viewbag.message for null

Related

How to fix submit form call http method get with query params

I have an asp net core mvc application. An action that create article. The problem is that when I submit the form , my application always calls the get method. How to fix this ?
Create.cshtml
#model MyBlog.Models.Article
#{
Layout = "~/Views/Shared/_AdminLayout.cshtml";
ViewBag.Title = "Create article";
}
<h2>Create article</h2>
#using (Html.BeginForm("Create", "Article", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Title, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Title, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Title, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Content, htmlAttributes: new { #class = "control-label col-md-2" })
<div ass="col-md-10">
#Html.TextAreaFor(model => model.Content,new { #id = "Content", #class = "form-control", #rows = "200" })
#Html.ValidationMessageFor(model => model.Content, "", new { #class = "text-danger" })
<script>
CKEDITOR.replace("Content");
</script>
</div>
</div>
<div class="col-md-offset-2 col-md-10">
<input id="Submit" type="submit" value="submit" />
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Article controller:
// POST: Article
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind("Title,Content")] Article article)
{
try
{
return RedirectToAction("Index");
}
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
}
return View();
}
// GET: Article/Create
[HttpGet]
public ActionResult Create()
{
return View();
}
When I submit form. I see a url like this appears:
xxx//localhost:7158/article/create?Title=a&Content=b__RequestVerificationToken=CfDJ8JLgrvFS_U1JlinCQaKFM9rmomKaF5pDFJjX5Mbp7_OCoQq2hNZ6ygB05XZd-Qy8osia_h_1i1nzXuk5lZWQRBSTsId3hu-lbcapc3xDViukVhv6xeMv_ekiCyW6HdFkFh8iBzjXhJ9bRnZyrnP651U
Debug on VS studio
I have found this bug. If I change Layout shared to null. It working. So I have modified my shared layout. Tks for your help !

MVC Is there a way to make sure a specific ViewModel property doesn't get passed in a Html.BeginForm(action, controller, ModelData)?

ANSWERED
See answers section below
I've been struggling for hours with this problem and I haven't found anything that relates, so apologies if this post is a duplicate.
I'll start by constructing a problem related to my own.
Let's say we create a ViewModel:
public class XmlViewModel(){
[Required]
public string Code { get; set; }
public string XML { get; set; }
}
and a constructor method which loads the View and as well as another that gets called when the submit is registered on the View.
public class Extractor{
public ActionResult Index()
{
XmlViewModel xmlVM = new XmlViewModel ()
{
XML = "Sample XML";
};
return View(xmlVM);
}
public ActionResult GetXml(XmlViewModel xmlVM){
xmlVM.XML = GetXMLByCode();
return View ("Index", xmlVM)
}
}
Then the view Index as below
#model Project.ViewModel.XmlViewModel
#{
ViewBag.Title = "Index";
}
#using (Html.BeginForm("GetXml", "Extractor", Model))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Code, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Code, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Code, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.XML, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-9">
<pre id="XML">#Html.Raw(Html.Encode(Model.XML))</pre>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Generate XML" class="btn btn-default"/>
</div>
</div>
</div>
}
So in this scenario I'm starting the page with:
When the user clicks Submit using a XML Code, I want the Code to be run against some collection of XML, then that returned XML replaces the "SampleXML"
Problem is when the form gets submitted again(Twice) (Now with the XML field holding a few hundred characters) it overloads the Query and returns this:
Because yep you guessed it, the XML fills up the Request with the XML from the previous Form result.
So my question is, is there any way to clear the ViewModel Property so it isn't passed in the Query, or some attribute to add that will tell the ViewModel to not pass the property through the Html.BeginForm()?
If possible I would like to stay away from passing the ViewModel properties individually as the actual problem's ViewModel is more complicated and it would be troublesome going down that route.
After my suggestions, if you are still getting header to large, I can help diagnose.
Add an xml file to your project. Add tons of xml to it. Right click to get properties. For build action, change to embedded resource.
Where I have WebApplication2.XMLFile1.xml, you should have your assembly name dot then your file name. You can right click on your project, and see properties to get assembly name.
Here is my code
namespace WebApplication2.Controllers
{
public class XmlViewModel
{
[Required]
public string Code { get; set; }
public string XML { get; set; }
}
public class HomeController : Controller
{
public static string GetXMLByCode()
{
var assembly = Assembly.GetExecutingAssembly();
var resourceName = "WebApplication2.XMLFile1.xml";
string result = String.Empty;
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
using (StreamReader reader = new StreamReader(stream))
{
result = reader.ReadToEnd();
}
return result;
}
public ActionResult GetXml(XmlViewModel xmlVM)
{
xmlVM.XML = GetXMLByCode();
return View("Index9", xmlVM);
}
public ActionResult Index9()
{
XmlViewModel xmlVM = new XmlViewModel { XML = "Sample XML" };
return View(xmlVM);
}
here is my view
#model WebApplication2.Controllers.XmlViewModel
#{
ViewBag.Title = "Index9";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm("GetXml", "Home", Model))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Code, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Code, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Code, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.XML, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-9">
<pre id="XML">#Html.Raw(Html.Encode(Model.XML))</pre>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Generate XML" class="btn btn-default" />
</div>
</div>
</div>
}
ANSWERED
I eventually figured it out by doing the following in the view:
#{
ViewBag.Title = "Index";
ViewBag.XML= XmlViewModel.XML;
XmlViewModel.XML = "";
}
---
<div class="form-group">
#Html.LabelFor(model => model.XML, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-9">
<pre id="XML">#Html.Raw(Html.Encode(ViewBag.XML))</pre>
</div>
</div>
Now when the view is loaded, the Viewbag will hold the XML being returned and I can safely empty the model data before returning it to the Html.BeginForm()
Keeping for anyone in the same situation

The model item passed into the dictionary is of type *** but this dictionary requires a model item of type ***

Hi I want to build a simple url with asp.net MVC to list and edit data from my table.
I got issue at edit page. Can someone help to take a look?
C# is new to me, and I created this by following a youtube tutorial
Error:
The model item passed into the dictionary is of type
'System.Data.Entity.Infrastructure.DbQuery`1 [MovieApp.Models.IPR_CompanyGen_200200501]', but this dictionary requires a model item of type 'MovieApp.Models.IPR_CompanyGen_200200501'.
HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MovieApp.Models;
namespace MovieApp.Controllers
{
public class HomeController : Controller
{
private dtsdbEntities _db = new dtsdbEntities();
// GET: Home
public ActionResult Index()
{
return View(_db.IPR_CompanyGen_200200501.ToList());
}
// GET: Home/Edit/5
public ActionResult Edit(int id)
{
var CompanyToEdit = (from m in _db.IPR_CompanyGen_200200501 where
(m.CompanyID.Equals(id.ToString())) select m);
return View(CompanyToEdit);
}
// GET: Home/Edit/5
[HttpPost]
public ActionResult Edit(IPR_CompanyGen_200200501 CompanyToEdit)
{
var OriginalCompany = (from m in _db.IPR_CompanyGen_200200501 where
(m.CompanyID.Equals(CompanyToEdit.CompanyID.ToString())) select m);
_db.Entry(OriginalCompany).CurrentValues.SetValues(CompanyToEdit);
_db.SaveChanges();
return RedirectToAction("Index");
}
}
internal class MoviesDBEntities
{
}
}
Edit.cshtml
#model MovieApp.Models.IPR_CompanyGen_200200501
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>IPR_CompanyGen_200200501</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.CompanyID)
<div class="form-group">
#Html.LabelFor(model => model.CompanyName, htmlAttributes: new { #class = "control-label
col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.CompanyName, new { htmlAttributes = new { #class =
"form-control" } })
#Html.ValidationMessageFor(model => model.CompanyName, "", new { #class = "text-
danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ACCOUNT_ID, htmlAttributes: new { #class = "control-label
col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ACCOUNT_ID, new { htmlAttributes = new { #class =
"form-control" } })
#Html.ValidationMessageFor(model => model.ACCOUNT_ID, "", new { #class = "text-
danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
You forgot to use .First() or .FirstOrDefault().
This is necessary because the LINQ query itself returns a database object System.Data.Entity.Infrastructure.DbQuery hence why we need to save to memory and store to a variable with .First(),.FirstOrDefault(),.ToList(), etc.
public ActionResult Edit(int id)
{
var CompanyToEdit = (from m in _db.IPR_CompanyGen_200200501 where
(m.CompanyID.Equals(id.ToString())) select m);
// add .FirstOrDefault()
return View(CompanyToEdit.FirstOrDefault());
}

Displaying a catch exception in MVC

I am quite new to Development in general and MVC.
I am trying to display an exception that is been thrown by my repository, in my MVC site. I have created View : "Error" to handle the error-message.
My main controller look as follows:
using BankMVC.Models;
using BankMVC.WithdrawingService;
using Pocos;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace BankMVC.Controllers
{
public class WithdrawingController : Controller
{
WithdrawingServiceClient withdrawingClient;
public WithdrawingController()
{
withdrawingClient = new WithdrawingServiceClient();
}
public ActionResult Withdraw(int Id, int TypeId)
{
BankAccount bankAccount = new BankAccount();
bankAccount.BankAccountId = Id;
bankAccount.BankAccountTypeId = TypeId;
DepositingWithdrawingViewModel withdrawViewModel =
new DepositingWithdrawingViewModel();
withdrawViewModel.BankAccountId = bankAccount.BankAccountId;
withdrawViewModel.Balance = bankAccount.Balance;
withdrawViewModel.BankAccountTypeId = bankAccount.BankAccountTypeId;
return View(withdrawViewModel);
}
[HttpPost]
public ActionResult Withdraw(DepositingWithdrawingViewModel withdrawViewModel)
{
BankAccount bankAccount = new BankAccount();
bankAccount.BankAccountId = withdrawViewModel.BankAccountId;
bankAccount.BankAccountTypeId = withdrawViewModel.BankAccountTypeId;
try
{
withdrawingClient.Withdraw(withdrawViewModel.Amount, bankAccount);
return RedirectToAction("Index", "BankAccount");
}
catch (Exception e)
{
return RedirectToAction("Error", new { message = e.Message });
}
}
}
}
my main controller view looks as follows:
#model BankMVC.Models.DepositingWithdrawingViewModel
#{
ViewBag.Title = "Withdraw";
}
<h2>Withdraw</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Withdraw from Bank Account</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.BankAccountId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.BankAccountId, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.BankAccountId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.BankAccountTypeId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.BankAccountTypeId, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.BankAccountTypeId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Balance, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Balance, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Balance, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Amount, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Amount, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Amount, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Withdraw" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index", "BankAccount")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
I have created an Error Model which looks as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace BankMVC.Models
{
public class ErrorModel
{
public string Error { get; set; }
}
}
How should my Error-View look Like to display the error-message. It currently looks as follows:
#model BankMVC.Models.ErrorModel
#{
ViewBag.Title = "Error";
}
<h2>Error</h2>
any clarification is appreciated.
I see you are redirecting to an action named "Error" inorder to display your error page. But what i dont see is an action method in the name of "Error". Do the following
Create another method in the controller named "Error"
public ActionResult Error(string message)
{
var model = new ErrorModel();
model.Error = message;
return View(model); // make sure your error view is named as "Error". Else u need to specify the view name in the return command.
}
Please note that I have utilized your Error Model that u have posted .
Also in the Error View, you can utilize the error message by altering your view like this
#model BankMVC.Models.ErrorModel
#{
ViewBag.Title = "Error";
}
<h2>Error</h2>
<h2>Message : #Model.Error</h2>
This will display your error message as well

One model for two submit buttons in ASP.NET MVC

I have a form on my view:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.DateFrom, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.DateFrom, new { htmlAttributes = new { #class = "form-control date-picker" } })
#Html.ValidationMessageFor(model => model.DateFrom, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.DateTo, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.DateTo, new { htmlAttributes = new { #class = "form-control date-picker" } })
#Html.ValidationMessageFor(model => model.DateTo, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" formAction=#Url.Action("CreateReport") />
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.EMail, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.EMail, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.EMail, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Send to email" class="btn btn-default" formAction=#Url.Action("SendEmail") />
</div>
</div>
</div>
}
As you can see I have two butons, first button call CreateReport action and than Send button call SendEmail action. I want to create report and then send this report by e-mail.
Here is my controller actions:
public ActionResult Index()
{
Report
report=ReportRepository.GetReport(DateTime.Parse("02.08.1996"), DateTime.Parse("07.08.1996"));
return View(report);
}
public ActionResult CreateReport(Report report)
{
report = ReportRepository.GetReport(report);
return View("Index", report);
}
public ActionResult SendEmail(Report report)
{
return View("Index", report);
}
And my model class:
public class Report
{
public DateTime DateFrom { get; set; }
public DateTime DateTo { get; set; }
public List<OrderDetails> Orders { get; set; }
[Display(Name = "Email address")]
[EmailAddress(ErrorMessage = "Invalid Email Address")]
public string EMail { get; set; }
}
So I mean that I fill Orders list in CreateReport action and display it and after it I press "Send to email" button, that's call "SendEmail" action, where I save Orders list to file and send it.
The problem is that in "SendEmail" action List is null.
How can I fix it?
The simplest way that I could think of is to remove your submit action for create report and handle this with ajax call. So that you will have only one submit action.
Or else you can try with 2 forms in your View.
Personally, I prefer the 1st option.
I'v found a solution. The solution is not to pass model to controller but store my List in Session. Like this:
public ActionResult Index()
{
Report report=ReportRepository.GetReport(DateTime.Parse("02.08.1996"), DateTime.Parse("07.08.1996"));
Session["Orders"] = report.Orders;
return View(report);
}
public ActionResult CreateReport(Report report)
{
report = ReportRepository.GetReport(report);
Session["Orders"] = report.Orders;
return View("Index", report);
}
public ActionResult SendEmail(Report report)
{
List<OrderDetails> orders = (List<OrderDetails>)Session["Orders"];
report.Orders = orders;
return View("Index", report);
}

Resources