ASP.Net MVC Displaying a session value in a master page - asp.net-mvc

When I display a session value in a master page (<%: Session["companyname"].ToString() %>) the following information is displayed on the page { CompanyName = TestCompany}. How do I get just the value?
Thanks for your help!

If you can show the code where the value is stored in the session, it's more likely that I could help. I would suggest, though, that you might want to reconsider using the value from the session directly in your view. It would be better, in my opinion, to have a base view model that all of your view models derive from that has the CompanyName property, and any other common properties required by your master page, on it. Your master page, then, could be strongly-typed to the base view model and you could use the values from the model. I've used this pattern with good success on a couple of projects. Couple it with a base controller where the common properties are populated for view results in OnActionExecuted(), it can be very effective in both reducing code duplication and the use of magic strings in your views.
Model:
public abstract class CommonViewModel
{
public string CompanyName { get; set; }
public string UserDisplayName { get; set; }
...
}
Controller:
public abstract class BaseController
{
public override void OnActionExecuted( ActionExecutedContext filterContext )
{
if (filterContext.Result is ViewResult)
{
var model = filterContext.ViewData.Model as CommonViewModel;
if (model != null)
{
model.CompanyName = Session["CompanyName"] as string;
model.UserDisplayName = Session["UserDisplayName"] as string;
}
}
}
}
Master Page:
<%# Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage<Foo.CommonViewModel>" %>
<!-- ... -->
<div>
<%: Model.CompanyName %>
</div>
<!-- ... -->
<div>
<%: Model.UserDisplayName %>
</div>

Related

What's the best regarded way to organize multiple ASP .Net MVC View models within a single view?

My app has a main dashboard which is comprised of 8 different partial views; each backed by their own view model and in my controller I'm just calling
public ActionResult mainDashboard(){
return View()
}
to return the dashboard. My question is would it be recommended to create a dashboard view model that also contains references to the view models of the partial views? What's considered a recommended best practice in this situation?
Ohkk here is a good idea as well to use html.Action instead of html.partial
This would look more like this:
public ActionResult Dashboard()
{
return View();
}
public PartialViewResult Clubs()
{
....
return PartialView(db.Clubs.ToList());//this assumes the partial view is named Clubs.cshtml, otherwise you'll need to use the overload where you pass the view name
}
public PartialViewResult Alerts()
{
....
return PartialView(db.Alerts.ToList());
}
Dashboard.cshtml
<div class="dashboard_alerts">
#Html.Action("Alerts")
<div class="dashboard_pending_clubs">
#Html.Action("Clubs")
</div>
<div class="dashboard_verified_members">
#Html.Action("Members")
</div>
OR
You would need to create a ViewModel specific for the Dashboard page precisely this would be more efficient way
public class DashboardViewModel
{
public IEnumerable<GMC.Models.Clubs> Clubs { get; set; }
public IEnumerable<GMC.Models.MemberUsers> Users { get; set; }
public IEnumerable<GMC.Models.Alerts> Alerts { get; set; }
}
Then, in the Dashboard action method, you would populate each list:
myModel.Users = db.MemberUsers.ToList();
...
You would then need to update the view to take in this new ViewModel
#model DashboardViewModel
Finally, from within the view, you would need to pass in the data to each partial:
#Html.Partial("DashboardAlerts", Model.Alerts)
#Html.Partial("DashboardClubs", Model.Clubs)

.net MVC 4 step wizard correct way to populate viewmodels?

I followed Darin's post at
multi-step registration process issues in asp.net mvc (splitted viewmodels, single model)
Its a very elegant solution, however im having trouble seeing how you would populate the individual step viewmodels with data. Im trying to emulate amazons checkout step-system which starts with selecting an address, then shipping options, then payment information.
For my first viewmodel i require a list of addresses for my current logged in user which i poll the database for to display on screen
In my head, this is the viewmodel that makes sense to me.
[Serializable]
public class ShippingAddressViewModel : IStepViewModel
{
public List<AddressViewModel> Addresses { get; set; }
[Required(ErrorMessage="You must select a shipping address")]
public Int32? SelectedAddressId { get; set; }
#region IStepViewModel Members
private const Int32 stepNumber = 1;
public int GetStepNumber()
{
return stepNumber;
}
#endregion
}
However there seems to be no good way to populate the addresses from the controller.
public class WizardController : Controller
{
public ActionResult Index()
{
var wizard = new WizardViewModel();
wizard.Initialize();
return View(wizard);
}
[HttpPost]
public ActionResult Index(
[Deserialize] WizardViewModel wizard,
IStepViewModel step)
{
wizard.Steps[wizard.CurrentStepIndex] = step;
if (ModelState.IsValid)
{
if (!string.IsNullOrEmpty(Request["next"]))
{
wizard.CurrentStepIndex++;
}
else if (!string.IsNullOrEmpty(Request["prev"]))
{
wizard.CurrentStepIndex--;
}
else
{
// TODO: we have finished: all the step partial
// view models have passed validation => map them
// back to the domain model and do some processing with
// the results
return Content("thanks for filling this form", "text/plain");
}
}
else if (!string.IsNullOrEmpty(Request["prev"]))
{
// Even if validation failed we allow the user to
// navigate to previous steps
wizard.CurrentStepIndex--;
}
return View(wizard);
}
}
So i removed the list of address view models
[Serializable]
public class ShippingAddressViewModel : IStepViewModel
{
[Required(ErrorMessage="You must select a shipping address")]
public Int32? SelectedAddressId { get; set; }
#region IStepViewModel Members
private const Int32 stepNumber = 1;
public int GetStepNumber()
{
return stepNumber;
}
#endregion
}
This is what i came up with a custom editor template for the view model. It calls a Html.RenderAction which returns a partial view from my user controller of all the addresses and uses Jquery to populate a hidden input field for the view model's required SelectedAddressId property.
#model ViewModels.Checkout.ShippingAddressViewModel
<script src="../../Scripts/jquery-1.7.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
//Check to see if the shipping id is already set
var shippingID = $("#SelectedAddressId").val();
if (shippingID != null) {
$("#address-id-" + shippingID.toString()).addClass("selected");
}
$(".address-id-link").click(function () {
var shipAddrId = $(this).attr("data-addressid").valueOf();
$("#SelectedAddressId").val(shipAddrId);
$(this).parent("", $("li")).addClass("selected").siblings().removeClass("selected");
});
});
</script>
<div>
#Html.ValidationMessageFor(m => m.SelectedAddressId)
#Html.HiddenFor(s => s.SelectedAddressId)
<div id="ship-to-container">
#{Html.RenderAction("UserAddresses", "User", null);}
</div>
</div>
And the users controller action
[ChildActionOnly]
public ActionResult UserAddresses()
{
var user = db.Users.Include("Addresses").FirstOrDefault(
u => u.UserID == WebSecurity.CurrentUserId);
if (user != null)
{
return PartialView("UserAddressesPartial",
Mapper.Map<List<AddressViewModel>>(user.Addresses));
}
return Content("An error occured");
}
The partial view
#model IEnumerable<AddressViewModel>
<ul>
#foreach (var item in Model)
{
<li id="address-id-#item.AddressID">
#Html.DisplayFor(c => item)
<a class="address-id-link" href="#" data-addressid="#item.AddressID">Ship To this Address
</a></li>
}
</ul>
My solution just seems super out of the way/sloppy to me, is there a better more concise way to populate the viewmodel than using partial views from a different controller for this?
There's nothing wrong with using a child action like this to populate the user's addresses. In fact, I think this is actually the optimal approach. You've got full separation of concerns and single responsibility in play. Just because something requires more "pieces" (extra action, views, etc.) doesn't make it sloppy or otherwise wrong.
The only other way to handle this would be with dependency injection. Namely, your ShippingAddressViewModel would need a dependency of the currently logged in user, so that it could populate the list of addresses from that in its constructor. However, since ShippingAddressViewModel is not exposed in your view, you would have to pass the dependency through Wizard which is a bit of code smell. Wizard is not dependent on a user, but it would have dependence forced upon it by virtue of having your view model abstracted away inside it.
Long and short, while there's a way you could do this without the child actions and partial views, it would actually be nastier and sloppier than with them.

Model binding and display trimmed string property

My strongly typed View inherits from a "Person" object that is created with Linq to SQL. In my "Edit" View, i have to display of course old values:
<%= Html.TextBox("FirstName") %>
"FirstName" is NCHAR, so it need to be trimmed. So i ended up with:
<%= Html.TextBox("FirstName", Model.FirstName.Trim()) %>
and this works. But when form is submitted (after POST) and some errors occur, i need to show it again:
[AcceptVerbsAttribute(HttpVerbs.Post), Authorize(Roles = "office"), HandleError]
public ActionResult Edit(Models.Person person)
{
if (!(_personService.ValidatePerson(person))) // Persona non valida
{ return View(person); }
}
If for some reason the user left the textbox "FirstName" blank, the resulting property Person.FirstName become null and Model.FirstName.Trim() throws an Exception (Object reference not set to an instance of an object).
Any way to modify the bind and have all string trimmed by default? Or any ideas to how fix this?
Update: seems confirmed to be a MVC 2 behaviour.. still looking for a good way to handle this. Actually using an extension method:
public static string TrimOrDefault(this string value)
{
return value != null ? value.Trim() : string.Empty;
}
Something is odd here.
Model.FirstName shouldn't be null; the model binder is smart enough to set an empty input field ( textbox ) to "". Make sure your property names match up between your model and the textboxes your using.
Which version of MVC are you using? 1 or 2? I'm running a MVC 1 version in VS 2008 and the only way I can get FirstName to be null is by not including it in the form at all.
I could see if you initial GET Edit view threw this error and you had FirstName set to nullable in your dbml and database but since it is a Post this doesn't make sense to me right now. ;)
Update:
I've confirmed this:
With an empty form:
VS 2008 - Mvc 1 - FirstName = ""
VS 2010 - Mvc 2 - FirstName = null
Uh oh... Thats going to break a lot of code...
The Code:
View ( same for both ):
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Fields</legend>
<p>
<label for="FirstName">FirstName:</label>
<%= Html.TextBox("FirstName", Model.FirstName) %>
<%= Html.ValidationMessage("FirstName", "*") %>
</p>
<p>
<label for="LastName">LastName:</label>
<%= Html.TextBox("LastName", Model.LastName) %>
<%= Html.ValidationMessage("LastName", "*") %>
</p>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
VS 2010 - Mvc 2
public class HomeController : Controller
{
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
public ActionResult AddPerson()
{
var person = new Person();
return View(person);
}
[HttpPost]
public ActionResult AddPerson(Person person)
{
return View(person);
}
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
VS 2008 - Mvc 1
public class HomeController : Controller
{
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
public ActionResult AddPerson()
{
var person = new Person();
return View(person);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddPerson( Person person )
{
return View(person);
}
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
No clean fix atm. The model binder is actually setting those properties to null. Set First and Last to "" in the constructor and exclude those properties from binding: [Bind(Exclude="FirstName, LastName")] they stay "".
Is this documented someplace?
Try a custom modelbinder.
See this : ASP.NET MVC: Best way to trim strings after data entry. Should I create a custom model binder?
In Models.Person have the default value be String.Empty which should elminate the null error at least.
If you want to have it automated, then you can add that into your dbml file. There is a designer.cs file attached and each field has a getter and setter. you can add code in there if you wish.
you could also create a partial class based on your table and handle the trim within that. it means that if you make a change to the dbml file then you don't lose your changes.
if you're not using a dbml file then let us know.
EDIT
If you have a class called person in your dbml file then this will already be declared as partial.
create another class, in the same project and do something like the following;
public partial class Person
{
public string NewName
{
get { return this._name.Trim(); }
}
}
So from then on in you can use .NewName instead of name and it will come back trimmed. You can also add code in there to ensure it's not null, not red, not whatever and return the appropriate value.
I'm not aware of an extension method that does this, if someone else does then please let me know.
I create a simple HTML helper for fields that COULD be null.
public static string TrimOrDefault(string value)
{
return (value == null ? "" : value.Trim());
}
And then in your code you can use
<%= Html.TextBox("FirstName", Helpers.TrimOrDefault(Model.FirstName)) %>
It's re-usable for future nullable fields and reads easily.

Posting complex object (with hierarchy) to Controller in ASP.NET MVC

Am using strongly typed view to show a complex object in a data entry/edit form. for eg: Model.UserInformation.Name, Model.LivingPlace.FacilitiesSelectList, Model.Education.DegreesList... etc. These information are shown in multiselect listbox, grids.. etc. User can change the information in the edit screen. Is there any way to post the Model object with user changes to controller on sumbit button click. Please suggest.
Regards,
SHAN
The same object instance that has been passed to the view: No. ASP.NET MVC uses a default Model binder to instantiate new action parameters from request values. So for example if you had the following action method:
public ActionMethod DoWork(User model)
{
return View();
}
public class Address
{
public string Street { get; set; }
}
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Address[] Addresses { get; set; }
}
the binder will look in the request and try to bind model values. You could to the following in your View:
<%= Html.TextBox("FirstName") %>
<%= Html.TextBox("LastName") %>
<%= Html.TextBox("Addresses[0].Street") %>
<%= Html.TextBox("Addresses[1].Street") %>
This will automatically populate the values of your model in the controller action.
To avoid mass assignment of properties that shouldn't be bound from request values it is always a good idea to use the BindAttribute and set Exclude or Include properties.
Use <input type="text" name="UserInformation.Name"><input> to bind to subobjects.

ASP.NET MVC Masterpage code file

Please can anybody point out where this code might be going wrong. I am trying to create a partial class for the masterpage.
The master pages class:
namespace MuniWeb.Models.SiteMaster{
public class BaseViewData
{
public string Title { get; set; }
public string MetaKeywords { get; set; }
public string MetaDescription { get; set; }
}
public partial class Site : System.Web.Mvc.ViewMasterPage<MuniWeb.Models.SiteMaster.BaseViewData>
{
public Site()
{
ViewData.Model = new BaseViewData();
}
}}
The master page:
<%# Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage<MuniWeb.Models.SiteMaster.BaseViewData>" %>
The error:
Object reference not set to an instance of an object.
Line 33: <div id="footer">
Line 34: ApplicationID:
Line 35: <%= Model.Title %>
Line 36: </div>
Line 37: </div>
I am just using this as an example. The code I want to use needs to fire for every page to check certain parameters, this is why it is in the master page.
You shouldn't need to make a partial class. What does your controllers action code look like? The error looks like it could be from not handing the View (and therefore it's master page) a model.
Try something like this:
namespace MuniWeb.Website.ViewDataModels {
public class BaseViewData
{
public string Title { get; set; }
public string MetaKeywords { get; set; }
public string MetaDescription { get; set; }
}
public class SubViewData : BaseViewData
{
public IList<Thing> Things { get; set; }
}
}
Then define your master page like you had:
<%# Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage<MuniWeb.Website.ViewDataModels.BaseViewData>" %>
Now in your controller
public ActionResult Index()
{
SubViewData viewData = new SubViewData();
viewData.Title = "Page Title";
viewData.MetaKeywords = "This, that, and the other";
viewData.MetaDescription = "A really great page about this, that, and the other.";
viewData.Things = _myRepository.GetThings();
return View(viewData);
}
See how that goes...
I would ask why the MasterPage NEEDS strongly type ViewData. I understand that yes, sometimes strongly typed viewdata is needed in masterpages but generally you should be able to get way with just using the ViewData name value collection.
Shouldn't your master page be inheriting Site and not System.Web.Mvc.ViewMasterPage? No where does your master page definition actually reference the Site class.
In your code,
public partial class Site :
System.Web.Mvc.ViewMasterPage<MuniWeb.Models.SiteMaster.BaseViewData>
{
public Site()
{
ViewData.Model = new BaseViewData();
}
}}
ViewData.Model = new BaseViewData(); is not necessary. The BaseViewData should be passed in via the controller. In other words, all of your views should take look for a View that inherits the base view. The Master Page will have that same object cast as the base class BaseViewData. Your controller code appears to be correct in doing just that.
Another thing that appears to be different from my similar code is Inherits=System.Web.Mvc.ViewMasterPage<MuniWeb.Models.SiteMaster.BaseViewData> should be Inherits=my.codebehind.class, then your codebehind would inherit ViewMasterPage<MuniWeb.Models.SiteMaster.BaseViewData>.
I've just not seen the code as such, perhaps it works?

Resources