Is it OK to use repository in view model? - c#

Let's say I have complex view model with a lot of data such as lists of countries, products, categories etc. for which I need to fetch from the database every time I create the ViewModel.
The main problem I want to fix is that when I handle POST actions and some TestModel was posted with incorrect values, which causes ModelState.IsValid to be false, then I have to return the same view with currently posted model. This forces me to get my list of categories again, since I was doing that in the GET action. This adds a lot of duplicated code in controller and I want to remove it. Currently I am doing the following:
My model and view models:
Model, entity stored in the database:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<Category> SubCategories { get; set; }
}
View models:
public class CategoryModel
{
public int Id { get; set; }
public string Name { get; set; }
}
public class TestModel
{
[Required]
[MaxLength(5)]
public string Text { get; set; }
public int SelectedCategory { get; set; }
public IEnumerable<CategoryModel> Categories { get; set; }
public SelectList CategoriesList
{
get
{
var items = Categories == null || !Categories.Any()
? Enumerable.Empty<SelectListItem>()
: Categories.Select(c => new SelectListItem
{
Value = c.Id.ToString(),
Text = c.Name
});
return new SelectList(items, "Value", "Text");
}
}
}
My controller:
public class HomeController : Controller
{
private readonly Repository _repository = ObjectFactory.GetRepositoryInstance();
public ActionResult Index()
{
var model = new TestModel
{
Categories = _repository.Categories.Select(c => new CategoryModel
{
Id = c.Id,
Name = c.Name
})
};
return View(model);
}
[HttpPost]
public ActionResult Index(TestModel model)
{
if (ModelState.IsValid)
{
return RedirectToAction("Succes");
}
model.Categories = _repository.Categories.Select(c => new CategoryModel
{
Id = c.Id,
Name = c.Name
});
return View(model);
}
public ActionResult Succes()
{
return View();
}
}
I want to remove duplicated Categories fetching and mapping, basically this code:
.Categories = _repository.Categories.Select(c => new CategoryModel
{
Id = c.Id,
Name = c.Name
})
from controller. Also I want to remove ModelState validity check, I want to execute the action only if ModelState.IsValid to keep controller code AS CLEAN AS POSSIBLE. So far I have the following solution for removing ModelState validity check:
Create custom ValidateModelAttribute
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var viewData = filterContext.Controller.ViewData;
if(viewData.ModelState.IsValid) return;
viewData.Model = filterContext.ActionParameters["model"];
filterContext.Result = new ViewResult
{
ViewData = viewData,
};
}
}
Now model is validated before the action executes. In case of validation errors, we use same view with the same recently posted model. Therefore, the controller POST action looks like this:
[HttpPost]
[ValidateModelAttribute]
public ActionResult Index(TestModel model)
{
// Do some important stuff with posted data
return RedirectToAction("Success");
}
This is nice, but now my Categories property of my TestModel is empty, because I have to fetch the categories from the database, and map them accordingly. So is it OK to modify my view model to look something like this:
public class TestModel
{
private readonly Repository _repository = ObjectFactory.GetRepositoryInstance();
...
public int SelectedCategory { get; set; }
public IEnumerable<CategoryModel> Categories {
get
{
return _repository.Categories.Select(c => new CategoryModel
{
Id = c.Id,
Name = c.Name
});
}
}
...
}
This will allow us to have very clean controller, but wouldn't it cause some kind of performance or architectural issues? Wouldn't it break the single responsibility principle for view models? Should ViewModels be responsible for fetching data it needs?

It's not ok. the view model should be mainly a DTO populated by a service/query or even the controller. There was no problem with the previous version, your controller is just a couple of lines of code.
But your repository is not really a repository, it's a an ORM. A proper repository (well here it would be just some query object) would return directly the list of Categories for the view model.
About your auto validation attribute, don't reinvent the wheel, someone else (in this case me) did it before .

No, you shouldn't put repository reference and logic into the view models. I suppose the only thing you need is to be able to rebuild the model if the validation fails. You can try one of the automated ModelState validation, for example:
http://benfoster.io/blog/automatic-modelstate-validation-in-aspnet-mvc

There are a few flows I can see with your approach,
Using the repository and doing actual querying in the controller,
var model = new TestModel
{
Categories = _repository.Categories.Select(c => new CategoryModel
{
Id = c.Id,
Name = c.Name
})
};
Better approach is either to move this to repository or even better put it into a more logical level such as services.
With your new solution it's even worse as you refer the repository inside the view model. Ideally I'd do it like this,
public class TestService : ITestService{
private IReposotory repo;
public TestService(IReposotory repo){
this.repo = repo;
}
public TestModel GetModel()
{
return new TestModel()
{
Categories = _repository.Categories.Select(c => new CategoryModel
{
Id = c.Id,
Name = c.Name
})
};
}
}
public class HomeController : Controller
{
private readonly ITestService _service;
public HomeController (ITestService service){
_service = service;
}
public ActionResult Index()
{
return View(_service.GetModel());
}
[HttpPost]
public ActionResult Index(TestModel model)
{
if (ModelState.IsValid)
{
return RedirectToAction("Succes");
}
return View(model);
}
public ActionResult Succes()
{
return View();
}
}

Related

Selected item transfer issue, There is no ViewData item of type

I am building ASP.NET MVC project, All other posts about this topic did not help me. i have 2 models, Client and City.
public class Client
{
[Key]
public int Id { get; set; }
public string Surname { get; set; }
public string Name { get; set; }
public City City { get; set; }
}
public class City
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
And when i want to create a client a have an exception There is no ViewData item of type 'IEnumerable' that has the key 'City'.
This is my get and post method
private readonly ApplicationDbContext _context;
private List<City> _cities;
public ClientsController(ApplicationDbContext context)
{
_context = context;
}
// GET: Clients/Create
public IActionResult Create()
{
if (_context.City != null) _cities = _context.City.ToList();
ViewBag.Cities = new SelectList(_cities, "Id", "Name");
return View();
}
// POST: Clients/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Surname,Name,Patronymic,Telephone,City,Adress,SeriaNumberPassport,IdentificalCode")]
Client client)
{
if (ModelState.IsValid)
{
_context.Add(client);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(client);
}
And View code:
<div class="form-group" mb-3>
<label asp-for="City" class="control-label"></label>
#Html.DropDownListFor(model => model.City, ViewBag.Cities as SelectList, new { #class = "form-select" })
</div>
The data is displayed correctly, but I cannot create a client.
Think that the ModelState.IsValid is false, hence it returns to Create View rather than redirect to Index view (the flow for successful inserting Client).
While for the failure inserting case, you didn't provide the ViewBag.Cities value before returning to Create View (Check the Create method with [HttpPost]).
Talk about why the ModelState.IsValid was false, there is conflict in the type that you are passing CityId which is int type to City property with City type.
Updated:
Recommend creating and using the ViewModel class instead of Model. The main reason is to we can design the class in which the properties are only required for view, create/edit purposes.
Exposing the Model class is unsafe as the users will know how is your database entity looks like.
But the trouble with using ViewModel will be you need to map the property value from ViewModel to Model manually or with reflection. Of course, there are open-source libraries that can automate the mapping such as AutoMapper.
These are the steps you need to do for the fix:
Model
Add for CityId foreign key property.
public class Client
{
[Key]
public int Id { get; set; }
public string Surname { get; set; }
public string Name { get; set; }
public int CityId { get; set; } // Add this foreign key property
public City City { get; set; }
}
Note: If you use Entity Framework Code First approach, you need to create migration and update the database via command for this change.
ViewModel
Create ViewModel class with the properties require for Create Client.
public class CreateClientModel
{
public string Surname { get; set; }
public string Name { get; set; }
public int CityId { get; set; }
// Other properties that needed
}
View
2.1. Change the #model to CreateClientModel.
2.2. Use model.CityId instead of model.City. The CityId property is used to pass the selected city's Id.
#model CreateClientModel
<div class="form-group" mb-3>
<label asp-for="CityId" class="control-label"></label>
#Html.DropDownListFor(model => model.CityId, ViewBag.Cities as SelectList, new { #class = "form-select" })
</div>
Controller
3.1. Replace City with CityId in Bind attribute. (To add properties based on CreateClientModel).
3.2. Use CreateClientModel as request body.
3.3. Initialize the ViewBag.Cities value before returning to Create view for the ModelState.IsValid is false case.
public IActionResult Create()
{
if (_context.City != null) _cities = _context.City.ToList();
ViewBag.Cities = new SelectList(_cities, "Id", "Name");
return View(new CreateClientModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Surname,Name,CityId")]
ClientClientModel client)
{
if (ModelState.IsValid)
{
// Perform mapping from CreateClientModel to
_context.Add(new Client
{
Surname = client.Surname,
Name = client.Name,
CityId = client.CityId
// Other properties
});
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
// Initialize ViewBag.Cities value
if (_context.City != null) _cities = _context.City.ToList();
ViewBag.Cities = new SelectList(_cities, "Id", "Name");
return View(client);
}
Suggested have a read and follow this tutorial which is similar to your scenario:
Tutorial: Update related data - ASP.NET MVC with EF Core

MVC Two controllers One View

I am trying to have a details view in an existing controller that joins two controllers and passes into the view, but everything i have tried so far has not worked. I have 4 data models and what i would like is to use 2 of them Company and Staff. So when i select details on a specific Company it will return all Staff associated to that Company in the same view.
HRDataModel class
public partial class HRDataModel : DbContext
{
public HRDataModel()
: base("name=HRDataModel")
{
}
public virtual DbSet<Company> Companies{ get; set; }
public virtual DbSet<Attribs> Attribs{ get; set; }
public virtual DbSet<Staff> Staffs { get; set; }
....
Company Data Model
[Table("Company")]
public partial class Company
{
public Company()
{
Staffs = new HashSet<Staff>();
}
public virtual ICollection<Staff> Staffs { get; set; }
public int companyId{ get; set; }
[Required]
[StringLength(10)]
public string companyName{ get; set; }
.....
Staff Data Model
public partial class Staff
{
public Staff()
{
Skills = new HashSet<Skill>();
}
public virtual Company Company{ get; set; }
public virtual ICollection<Skill> Skills { get; set; }
public int staffId { get; set; }
.........
And i am trying to get my Details method in CompanyController to show details of all active Companies in the db and also all Staff attached to that Company
[Route("Company/Staff/1}")]
public ActionResult Details(int id)
{
Company co = db.Companies.Find(id);
...How to implement????
return View(bu);
}
If anyone can point me in the right direction that would be great. I have tried and tried but cannot get anything to work?
Since Company includes Staff you can use the include method to include related entities.
var company = db.Companies.Include(c => c.Staffs).FirstOrDefault(x => x.id == companyId);
return View(company);
And in your view:
#foreach(var staff in Model.Staffs) { ... }
You need to pass a data structure which has the company info and staff details to your view. You may pass your existing Comapny entity class to do this. But the problem is, It makes your razor view tightly coupled to your Entity which was generated by the ORM. What if you switch your Data access layer to something else tomorrow. So this solution is not great.
So you should use a view model ( A simple POCO class) which has properties which you need to render in the view. Then read your entity from db in your action method, map it to a vie wmodel instance and send it.
Create a view model like this.
public class CompanyInfo
{
public int Id {set;get;}
public string Name {set;get;}
public List<StaffItem> Staffs {set;get;}
public CompanyInfo()
{
this.Staffs = new List<StaffItem>();
}
}
public class StaffItem
{
public int Id {set;get;}
public string Name {set;get;}
}
In your action method read the Company entity and map it to the view model
public ActionResult Details(int id)
{
var vm = new ComapnyInfo();
var company = db.Companies
.Include(r => c.Staffs)
.FirstOrDefault(x => x.companyId==id);
if(co!=null)
{
//Map the property values now
vm.Name = co.companyName;
vm.Id = co.companyId;
if(co.Staffs!=null)
{
vm.Staffs = co.Staffs.Select(f=> new StaffItem {
Id=f.staffId,
Name = f.staffName}).ToList();
}
}
return View(vm);
}
Now your view should be bound to the CompanyInfo view model
#model YourNamespace.CompanyInfo
<h2>#Model.Name</h2>
<h3>Staffs</h3>
#foreach(var staff in ModelStaffs)
{
<p>#staff.Name</p>
}
If you do not like the manual mapping, You may consider using a mapping libarary like Automapper.
Hi #stackface you dont pass two controllers to get both views for that what you do is create one View Model which is essentially a container for multiple models and pass that into the view from the controller.
E.g. Model 1, Model2, ModelN all are needed so you have a class and in that class it has properties consisting of Model1, Model2 and Model3 so that way you pass in your class which has all the needed models.
E.g.
public class Company{...}
public class Staff{...}
public class ViewModel{
public Company Company {get;set;}
public List<Staff> Staff{get;set;}
}
controller:
{
var viewModel = new ViewModel();
viewModel.Company = db.Companies.FirstOrDefault(x => x.id == companyId);
viewModel.Staff = db.Staff.Where(x => x.CompanyId == campanyId).ToList() //or whatever your properties are called.
Return View(viewModel);
}
Update your view to take type ViewModel.
You can also compose a view by calling controller actions that return partial views.
The advantage is that you can reuse the partial views and their actions, e.g. to show the company details with the same layout on different pages. This increases consistency and maintainability.
The drawback is that you loose flexibility: if a certain page requires a different layout, you should create a new view. Performance might also be lower because you hit the backend with many small operations instead of a single big one.
The combined viewmodel to show both company and staff details only needs to know how to access the required data:
public class CompanyAndStaffDetailsViewModel {
public long CompanyId { get; set; }
public long StaffId { get; set; }
}
The following action renders the combined view:
public ActionResult Details(long companyId, long staffId) {
var viewModel = new CompanyAndStaffDetailsViewModel {
CompanyId = companyId,
StaffId = staffId
};
return View("Details", viewModel);
}
The "Details" View composes the usecase by calling actions to render partial views:
#model CompanyAndStaffDetailsViewModel
#Html.Action("CompanyInfoPartial", "Company", new { companyId = Model.CompanyId })
#Html.Action("StaffInfoPartial", "Staff", new { staffId = Model.StaffId })
The "Company" controller provides a reusable action to render company details:
public ActionResult CompanyInfoPartial(long companyId) {
Company co = db.Companies.Find(companyId);
var model = Mapper.Map<CompanyViewModel>(co); // map persistable entity to ViewModel
return PartialView("_CompanyInfoPartial", model);
}
Then the parital View _CompanyInfoParital.cshtml only has to deal with the Company Info stored in the CompanyViewModel and knows nothing about Staff:
#model CompanyViewModel
#Html.DisplayFor(m => m.CompanyName)
// etc ...
The idea for the StaffInfoPartial action is the same as for CompanyInfoPartial.

ASP MVC 4: Request value of DropDownListFor

I have two classes many-to-many the first is "Anuncios" and the second "SubCategorias"
public class Anuncios {
public int AnuncioId {get;set;}
public string Titulo {get;set;}
public ICollection<SubCategorias> SubCategorias {get;set;}
}
public class SubCategorias {
public int SubCategoriaId {get;set;}
public string Nome {get;set;}
public ICollection<Anuncios> Anuncios {get;set;}
}
In DAL layer I did method to save the "Anuncio" in DB.
public void Salvar(Anuncio entidade) {
entidade.SubCategorias = entidade.SubCategorias.Select(subcat => _contexto.SubCategorias.FirstOrDefault(x => x.SubCategoriaId == subcat.SubCategoriaId)).ToList();
_contexto.Anuncios.Add(entidade);
_contexto.SaveChanges();
}
I Create the Action "Create":
private readonly Context _ctx = new Context();
public ActionResult Create()
{
var model = new Anuncios {SubCategorias = _ctx.SubCategorias.ToList()};
return View(model);
}
In View I made DropDownList with "SubCategorias":
#Html.LabelFor(model => model.SubCategorias)
#Html.DropDownListFor(model => model.SubCategorias, new SelectList(Model.SubCategorias, "SubCategoriaId", "Nome"))
The DropDownListFor is populated with sucess..
Fine....
But when submit form the value selected in DropDownListFor not pass to method Create. The anuncio.SubCategorias is null!
private readonly AnunciosDal _anuncio = new AnunciosDal();
[HttpPost]
public ActionResult Create(Anuncio anuncio)
{
_anuncio.Salvar(anuncio);
return View(anuncio);
}
I have sought in various forums the solution, but could not find
Somebody help me?!
Sorry about my english rs...
Thank You!
Fabrício Oliveira
The first parameter of DropDownListFor needs to be the object holding the selected value, where the second parameter contains the list:
#Html.DropDownListFor(model => model.SOME_ID_FOR_SELECTED_VALUE,
new SelectList(Model.SubCategorias, "SubCategoriaId", "Nome"))
Currently the example you have also maps the same list as the first property. You should use an ID like #Maess suggested, and then bind it via:
#Html.DropDownListFor(model => model.SubCategoriaID, new SelectList(Model.SubCategorias, "SubCategoriaId", "Nome"))
Selecting a value will then post it back to the server to this SubCategoriaID field.
You need to have another property to store the selected value from the dropdown. It is best if you create a viewmodel with properties which are needed for your view.
public class CreateAnuncios
{
public string Title {set;get;}
public int SelectedSubCategoryId {set;get;}
public List<SelectListItem> SubCategories {set;get;}
public CreateAnuncios()
{
this.SubCategories = new List<SelectListItem>();
}
}
Now in your create action, create an object of this view model, Fill the SubCategories property and send to the view.
public ActionResult Create()
{
var vm=new CreateAnuncios();
vm.SubCategories = ctx.SubCategorias
.Select(s=> new SelectListItem
{ Value = s.SubCategoriaId .ToString(),
Text=s.Nome}).ToList();
return View(vm);
}
Your create view should be strongly typed to the CreateAnuncios class
#model YourNameSpaceHere.CreateAnuncios
#using(Html.Beginform())
{
#Html.TextBoxFor(s=>s.Title)
#Html.DropdownListFor(s=>s.SelectedSubCategoryId,Model.SubCategories,"Select")
<input type="submit" />
}
Now when user posts the form, Read the Properties of the posted model and use that to save to db.
[HttpPost]
public ActionResult Create(CreateAnuncios model)
{
//Check for model.Title and model.SelectedSubCategoryId and use it to save
// to do :Save and redirect
}
You need to provide a collection of SelectListItems that populate your DropDownList as well as a property to hold the currently selected SelectListItems' Id (which will be posted back to the server):
public class Anuncios {
public int AnuncioId {get;set;}
public string Titulo {get;set;}
public ICollection<SubCategorias> SubCategorias {get;set;}
public int SelectedSubCategoryId {get;set;}
public IEnumerable<SelectListItem> SubCategoryListItems {get;set;}
}
then, present them to the user via:
#html.DropDownListfor(x => x.SelectedSubCategoryId, Model.SubCategoryListItems)
The SubCategoryListItems will have to be populated from the server, typically something like this:
this.SubCategoryListItems = this.SubCategorias.Select(x => new SelectListItem { Text = x.Name, Value = x.Id });
You need an id property for the SubCategoria you have it in your binding, but not in the model
public class Anuncios {
public int AnuncioId {get;set;}
public string Titulo {get;set;}
public ICollection<SubCategorias> SubCategorias {get;set;}
public int SubCategoriaId{get;set;}
}

Following correct practise when building view models

I have run into a caveat with regards to my approach to ASP.NET MVC and viewmodels. Essentially what I do is build a viewmodel in controller/action which merges models together and then passes it to the view.
[HttpGet]
public ActionResult MyAction1()
{
List<StaffModel> staffList = new List<StaffModel>();
var qryStaff = context.Staff.Select(c => new { c.ID, c.name});
foreach (var item in qryStaff )
{
StaffModel myStaffViewModel = new StaffModel
{
ID = item.ID, Name = item.Name
};
staffList.Add(myStaffViewModel );
}
So I do the above process and also do it with employees, exactly the same and then put it into employeeList. I then create my viewModel as the view.
EmployeeStaffViewModel viewModel = new EmployeeStaffViewModel
{
Staff = staffList,
Employee = employeeList
};
I then return the view. I have used employee & staff as an example. I actually have more models I add to the viewModel EmployeeStaffViewModel . It's getting quite big all within the controller action. Should I be creating a ViewModel as a class and then instantiating it in my controller so all the linq and foreach goes in the Model. Therefore I can use it in another controller action.
Thank you for any advice. Will be greatly received.
Lets say you have 3 classes in your ~/Models folder
StaffModel.cs
public class StaffModel
{
public int ID { get; set; }
public string Name { get; set; }
public static Func<Staff, StaffModel> Project = item => new StaffModel
{
ID = item.ID,
Name = item.Name
};
}
EmployeeModel.cs
public class EmployeeModel
{
public int ID { get; set; }
public string Name { get; set; }
public static Func<Employee, EmployeeModel> Project = item => new EmployeeModel
{
ID = item.ID,
Name = item.Name
};
}
EmployeeStaffViewModel.cs
public class EmployeeStaffViewModel
{
public EmployeeStaffViewModel()
{
Staff = new List<StaffModel>();
Employee = new List<EmployeeModel>();
}
public List<StaffModel> Staff { get; set; }
public List<EmployeeModel> Employee { get; set; }
}
The StaffModel and EmployeeModel both have a static Func<> that will map your db entity to your models. These Funcs can be used in your linq queries and expressions which you'll see below.
Your controller action is where you will retrieve your entities from your context. You can simplify your code to not have as many lines as you do.
MyController.cs
[HttpGet]
public ActionResult MyAction1()
{
var model = new EmployeeStaffViewModel();
model.Staff = context.Staff.Select(StaffModel.Project); //Select Staff to StaffModel List
model.Employee = context.Employee.Select(EmployeeModel.Project); //Select Employee to EmployeeModel List
return View(model);
}

MVC Entity Framework DropDownListFor<>

I would like to follow best MVC best practise for creating DropLists.
I have 3 Models (I have cut them down for the purposes of this)
Model One
Student
public int ID {get;set;}
public string Name {get;set}
public Site SiteID {get;set;}
Model Two
Site
public int ID {get;set;}
public string SiteName {get;set}
Model Three
VM
public int ID {get;set}
public student Students {get;set;}
public DateTime Date { get { return DateTime.Now; } }
public bool Criteria {get;set;}
In my VM view I am using EditorFor html helpers to populate my VM and Student Models. The site model is pre populated at the database seed.
I am looking for the best way to include a dropdownlist of sites on my VM view, that will map to my student model.
How to I correctly set up my models to achieve this?
In short, you want the DropDownListFor extension method and to put a List<Site> into the view model.
Here is a Fiddle that demonstrates your case. The Fiddle has more details. The nuts and bolts are here:
ViewModel - Add a List<Site>
public class MyViewModel
{
public MyViewModel()
{
this.Sites = new List<Site>();
}
public int ID { get; set;}
public Student Students { get; set; }
public DateTime Date { get { return DateTime.Now; } }
public bool Criteria { get; set; }
public List<Site> Sites { get; set; }
}
View - Use DropDownListFor
#Html.DropDownListFor(m => m.Sites,
new SelectList(Model.Sites, "ID", "SiteName"))
In psuedo-code, the above says
The Sites object in the model contains the properties to display.
Create a new SelectList using the Sites object in the model. Use the ID property as the data value and the SiteName property as the data text.
Create a drop down list based on the above info.
Controller
This just passes a seeded view model to the view.
public ActionResult Index()
{
var vm = SeedFromDatabase();
return View(vm);
}
private MyViewModel SeedFromDatabase()
{
var vm = new MyViewModel();
vm.Sites.Add(new Site(0, "one"));
vm.Sites.Add(new Site(1, "two"));
vm.Sites.Add(new Site(2, "three"));
return vm;
}
ViewModel
public class VM
{
public int ID {get;set}
public student Students {get;set;}
public SelectList SiteList {get;set;}
public int SiteID {get;set;}
public DateTime Date { get { return DateTime.Now; } }
public bool Criteria {get;set;}
}
Load View Action
public ActionResult LoadVMView(){
var model = new VM();
var items = GetSitesFromDatabase().Select(s => new SelectListItem(){
Text = s.SiteName,
Value = s.ID.ToString()
});
model.SiteList = new SelectList(items);
return View(model);
}
View:
#Html.DropDownListFor(m => m.SiteID, Model.SiteList)
On Post
[HttpPost]
public ActionResult LoadVMView(VM model){
var selecteSiteID = model.SiteID;
}

Categories

Resources