Pass Model into Layout Page MVC - c#

I am doing Web project with MVC 5 . I need pass to some data to layout page (data as Category_id or Category_Name).
I read some answers that say I need to make View Model , but my project must be in MVC and not in MVVM,
Do you any ideas?
Thanks!

you have to create a base view model that you will have to use for ALL your views
using Microsoft.AspNetCore.Mvc.Rendering;
public interface IBaseViewModel
{
public int CategoryId { get; set; }
public List<SelectListItem> CategoryList { get; set; }
}
public class BaseViewModel : IBaseViewModel
{
public int CategoryId { get; set; }
public List<SelectListItem> CategoryList { get; set; }
}
action
public IActionResult Index()
{
var baseViewModel=new BaseViewModel();
InitBaseViewModel(baseViewModel);
return View(baseViewModel);
}
private void InitBaseViewModel(IBaseViewModel baseViewModel)
{
//this is for test
// in the real code you can use context.Categories.Select ....
var items = new List<SelectListItem> {
new SelectListItem {Text = "Category1", Value = "1"},
new SelectListItem {Text = "Category2", Value = "2"},
new SelectListItem {Text = "Category3", Value = "3"}
};
baseViewModel.CategoryList= items;
}
layout
#model IBaseViewModel // you can omit it but I like to have it explicitly
#if(Model!=null && Model.CategoryList!=null && Model.CategoryList.Count > 0)
{
<select class="form-control" style="width:450px" asp-for="CategoryId" asp-items="CategoryList">
}
for another view you can create this action code
public IActionResult MyAction()
var myActionViewModel= new MyActionViewModel {
..... your init code
}
InitBaseViewModel(myActionViewModel);
return View(myActionViewModel)
}
public class MyActionViewModel : BaseViewModel
//or
public class MyActionViewModel : IBaseViewModel
{
public .... {get; set;}
}

You can pass directly a obj to View if you want in this way:
public virtual async Task<IActionResult> Index()
{
var model = await MethodThatRedurnModel();
return View(model);
}

Related

Redirect to action pass complex model

I want to pass to RedirectToAction model with List type property
For example, I have this simple model:
public class OrgToChooseFrom
{
public string OrgId { get; set; }
public string FullName { get; set; }
}
And complex model as this:
public class SelectCounteragentViewModel
{
public List<OrgToChooseFrom> Counteragents { get; set; }
public OrgToChooseFrom SelectedOrg { get; set; }
}
When I pass simple model with RedirectToAction every value is in place
[HttpGet]
public IActionResult ConfirmChoice(OrgToChooseFrom vm)
{
return View(vm);
}
But when I try to pass complex model SelectCounteragentViewModel, there are empty list and null for the "SelectedOrg" field
[HttpGet]
public IActionResult SelectFromCAOrganizations(SelectCounteragentViewModel vm)
{
return View(vm);
}
How can I do it?
RedirectToAction cannot pass complex model.You can try to use TempData as
Kiran Joshi said.Here is a demo:
public IActionResult Test()
{
SelectCounteragentViewModel vm = new SelectCounteragentViewModel { Counteragents = new List<OrgToChooseFrom> { new OrgToChooseFrom { OrgId ="1", FullName = "d" } }, SelectedOrg = new OrgToChooseFrom { OrgId = "1", FullName = "d" } };
TempData["vm"] = JsonConvert.SerializeObject(vm);
return RedirectToAction("SelectFromCAOrganizations", "ControllerName");
}
[HttpGet]
public IActionResult SelectFromCAOrganizations()
{
SelectCounteragentViewModel vm = JsonConvert.DeserializeObject<SelectCounteragentViewModel>(TempData["vm"].ToString());
return View(vm);
}

Get Roles specified on an action of a controller

I have an MVC Controller and a class that creates a menu with items that must only be displayed to users with a specific role for an action of a controller. In the below case I don't want to display the menu item of Details to users with Role2. What I end up doing is to specify the same roles on the menu items, the same roles that I already specified on the controllers. So I have 2 places where I define the roles and they must be the same, so it's error prone.
What I would like to do is to get the roles from the controller somehow but I have no clue how to do it or if it's even possible.
[Authorize(Roles = "Role1,Role2")]
public class MyController
{
public IActionResult Index()
{
return View();
}
[Authorize(Roles = "Role1")]
public IActionResult Details(int? id)
{
...
return View(...);
}
}
public class MenuItem
{
public string Action { get; set; }
public string Controller { get; set; }
public string Roles { get; set; }
}
...
var item = new MenuItem
{
Action = "Index",
Controller = "MyController",
Roles = "Role1,Role2", <---- this is what I do now.
Roles = GetRoles(MyController.Index.AuthorizedRoles) <---- this is what I need.
};
How about this factory method for your MenuItem:
public class MenuItem
{
public string Action { get; private set; }
public string Controller { get; private set; }
public string Roles { get; private set; }
private MenuItem() { }
public static MenuItem For<TMethod>(TMethod method) where TMethod : Delegate
{
var methodInfo = method.GetMethodInfo();
var attributes = methodInfo
.GetCustomAttributes(typeof(AuthorizeAttribute))
.Cast<AuthorizeAttribute>();
// If no attribute is defined on the action method, check the controller itself
if (attributes.Count() == 0)
{
attributes = methodInfo.DeclaringType
.GetCustomAttributes(typeof(AuthorizeAttribute))
.Cast<AuthorizeAttribute>();
}
return new MenuItem
{
Action = methodInfo.Name,
Controller = methodInfo.DeclaringType.Name,
Roles = string.Join(',', attributes.Select(a => a.Roles))
};
}
}
This can be called like:
var menuItem = MenuItem.For<Func<IActionResult>>(MyController.Details);

ASP.NET MVC - Hidden Field binded doesn't contain value

I'm having a trouble with my project (ASP.NET MVC 5/AJAX/BOOTSTRAP).
When click on Save button on Page, .Net calls in POST the proper action, but the Hidden Fields for PSATOKEN does not contain value (see #Html.HiddenFor(m => m.PSAToken) in the View), despite PSAToken contains a GUID value (saw in Debug Mode) in the Controller method.
Let's see some code below.
Many thanks to answerers!
Model
public interface IPSAPageViewModel
{
String PSAToken { get; set; }
int IdPSAAzienda { get; set; }
}
public abstract class BasePSAPageViewModel : IPSAPageViewModel
{
public String PSAToken { get; set; }
public int IdPSAAzienda { get; set; }
}
public class DatiGeneraliViewModel : BasePSAPageViewModel
{
public DatiGeneraliViewModel()
{
this.Item = new InformazioniGenerali();
}
public Crea.PSA.ServiceLayer.BO.InformazioniGenerali Item { get; set; }
public List<SelectListItem> FormeGiuridicheList { set; get; }
public List<SelectListItem> FormeConduzioneList { set; get; }
}
Controller
private ViewResult ViewPSAPage(IPSAPageViewModel vm)
{
base.createViewBagPaginePrecSucc();
return View(vm);
}
[HttpPost]
[ValidateAntiForgeryToken]
[HttpParamAction]
public ActionResult SalvaDatiGeneraliProsegui(DatiGeneraliViewModel vm)
{
return salvataggioDatiGenerali(vm, true);
}
[HttpPost]
[ValidateAntiForgeryToken]
[HttpParamAction]
public ActionResult SalvaDatiGenerali(DatiGeneraliViewModel vm)
{
//Here vm.PSAToken doesn't contain the value setted
return salvataggioDatiGenerali(vm);
}
private ActionResult salvataggioDatiGenerali(DatiGeneraliViewModel vm, bool proseguiCompilazione = false)
{
if (ModelState.IsValid)
{
var resp = aziendeManager.Save(vm.PSAToken, vm.Item, SessionManager.UserIdConnected, CONTROLLERNAME);
if (resp.Success)
{
var psaAzienda = resp.DataObject;
setVarsInSession(psaAzienda.idToken.ToString(), psaAzienda.idPsaAzienda.ToString(), psaAzienda.Aziende.ragioneSociale);
//Here there is some Value (POST)
vm.PSAToken = psaAzienda.idToken.ToString();
//vm.IdPSAAzienda = psaAzienda.idPsaAzienda.ToString();
if (proseguiCompilazione)
return RedirectToAction("DatiAziendaliRiepilogativi", new { id = psaAzienda.idToken });
}
else
ModelState.AddModelError("", resp.Message);
}
setSuccessMessage();
vm.FormeGiuridicheList = aziendeManager.GetAllFormeGiuridiche().ToSelectItems();
vm.FormeConduzioneList = aziendeManager.GetAllFormeConduzione().ToSelectItems();
return ViewPSAPage(vm);
}
View
to see the view click here
Here you can see the value at debug in VS
But in the generated HTML the Hidden Field of PSATOKEN is empty
I found the solution here:
patrickdesjardins.com/blog/… .

Dynamic CMS ViewModel

I'm building a CMS where I can dynamically say what types of editors will be shown. For instance on 1 type of page I might want a textbox and a textarea, and another a textbox and datepicker
I've defined the fields
public class CMSField
{
public string Label { get; set; }
}
public class CMSTextField : CMSField
{
public string Value { get; set; }
}
public class CMSDatePickerField : CMSField
{
public DatePickerControl Value { get; set; }
}
My view model
public class CmsVM
{
public List<CMSField> fields { get; set; }
public CmsVM()
{
fields= new List<CMSField>();
}
}
Then in the controller I can set this up like so (manually defined for now but will be defined elsewhere):
public ActionResult Add()
{
CmsVM model = new CmsVM();
model.fields.Add(new CMSTextField() { Label = "Title", Value = "" });
model.fields.Add(new CMSDatePickerField()
{
Label = "Date",
Value = new DatePickerControl
{
SelectedDate = DateTime.Now
}
});
return View("Add", "_FormLayout", model);
}
Then in my view I show the relevant editor
e.g.
#model CmsVM
#for (var i = 0; i < Model.fields.Count(); i++)
{
var cmsField = Model.fields[i];
if (cmsField is CMSTextField)
{
var textBox = (CMSTextField)cmsField;
#Html.TextBoxFor(model => textBox.Value)
}
else if (cmsField is CMSDatePickerField)
{
var dp = (CMSDatePickerField)cmsField;
#Html.EditorFor(model => dp.Value)
#Html.ValidationMessageFor(model => dp.Value)
}
}
All good so far, I get whatever controls I define in the controller shown. But I now need to deal with the postback. The model is always null
[HttpPost]
public ActionResult AddNew(CmsVM model)
{
...
}
Is there a better way to set this up, so that I can post the viewmodel back?

Simple form post always sends null to controller

I have no idea what's the reason, it's so straight and simple, but, curiously, doesn't work. I always recieve NULL as model in controller.
Here is the code:
Model
public class EnrolleePlaces
{
[HiddenInput(DisplayValue=false)]
public int id { get; set; }
public string SpecialtyCode { get; set; }
public string Specialty { get; set; }
public int Places { get; set; }
}
Controller
public ViewResult EditPlaces(int id)
{
return View(repo.EnrolleePlaces.FirstOrDefault(p => p.id == id));
}
[HttpPost]
public ActionResult NewPlaces(EnrolleePlaces places) // 'places' is ALWAYS null
{
if (ModelState.IsValid)
{
repo.SaveEnrolleePlaces(places);
return RedirectToAction("Settings");
}
return View("EditPlaces", places);
}
public ViewResult CreatePlaces()
{
return View("EditPlaces", new EnrolleePlaces());
}
And a view
#model Domain.Entities.EnrolleePlaces
#{
Layout = null;
}
Edit: #Model.Specialty
#using (Ajax.BeginForm("NewPlaces", "Enrollee", new { area = "Admin" },
new AjaxOptions() { UpdateTargetId = "AdminContent" } ,
new { enctype = "multipart/form-data" }))
{
#Html.EditorForModel()
// here is input type="submit"
}
I have over 15 controllers in my project, made by the same pattern, but only this one is strange
have you tried changing the name of the parameter that your action method receives ?
for example:
[HttpPost]
public ActionResult NewPlaces(EnrolleePlaces dd) // any name other than "places"
{
if (ModelState.IsValid)
{
repo.SaveEnrolleePlaces(places);
return RedirectToAction("Settings");
}
return View("EditPlaces", places);
}

Categories