ASP.NET MVC URL routing - asp.net-mvc

I have a question, can this be done using ASP.NET MVC (Razor, and MapRoute)?
Example
Category/ - calls controller Category and Index function
Category/{State_name} - calls controller Category and Cities(State_id) function, returns all cities inside that state.
So URL is displaying state name , but Cities function receive state id?

Yes u can, try
public class CategoryController : Controller {
// GET: /Category/
// OR
// GET: /Category/State_name
public ActionResult Index(string State_name) {
if (!string.IsNullOrWhiteSpace(State_name)) {
int? State_id = FindStateIdFromStateName(State_name); // retrive state_id from datastore where state_name == State_name
if (State_id.HasValue) { // means the currect state_name passed to action
var model = FindStateById(State_id.Value);
return View("Cities", model); // will renders Cities.cshtml with specified model
} else {
// means the specified state_name not found! u can do something else, or allow continue bellow lines
}
}
return View(); // will render normal Index.cshtml
}
}
Let me know if you have any questions or need clarifications on any part.
UPDATE
I have one issue with the way! You get the ID from db with State_name, then get the model from db by State_name! Why not retrieve
model from db by State_name at the first time?
look:
public class CategoryController : Controller {
// GET: /Category/
// OR
// GET: /Category/State_name
public ActionResult Index(string State_name) {
if (!string.IsNullOrWhiteSpace(State_name)) {
var model = FindStateByName(State_name);
if(model != null)
return View("Cities", model);
else
// means the specified state_name not found! u can do something else, or allow continue bellow lines
}
return View(); // will render normal Index.cshtml
}
}
and if you are on EF, then you can create this method:
public State FindStateByName(state_name){
using(var context = new YourEntityContext()){
return context.States.SingleOrDefault(s => s.Name.ToLower() == state_name.ToLower());
}
}
Why not using this way?

This should do it:
routes.MapRoute("Category_byState", "Category/{State_id}", new { controller = "Category", action = "Cities" });

Related

How To call An Action In Umbraco Controller?

I created an Umbraco DocumentType with the alias Personal and created a controller that inherits
Umbraco.Web.Mvc.RenderMvcController
I added two Actions, one is the default action and the other is called Test.
How can I fire the Test Action from the Personal controller?
public class PersonalController : Umbraco.Web.Mvc.RenderMvcController
{
// GET: Personal
public override ActionResult Index(RenderModel model)
{
return base.Index(model);
}
public String Test(RenderModel model)
{
return "fff";
}
}
When I put the url like this: localHost/personal/test it shows:
No umbraco document matches the url '/test'.
Which is right, so how can I call it?
I would do it like this
[HttpPost]
public ActionResult SubmitSearchForm(SearchViewModel model)
{
if (ModelState.IsValid)
{
if (!string.IsNullOrEmpty(model.SearchTerm))
{
model.SearchTerm = model.SearchTerm;
model.SearchGroups = GetSearchGroups(model);
model.SearchResults = _searchHelper.GetSearchResults(model, Request.Form.AllKeys);
}
return RenderSearchResults(model.SearchResults);
}
return null;
}
public ActionResult RenderSearchResults(SearchResultsModel model)
{
return PartialView(PartialViewPath("_SearchResults"), model);
}
See this blog post for the full context behind where this code snippet came from.
http://www.codeshare.co.uk/blog/how-to-search-by-document-type-and-property-in-umbraco/

How to load Two views From one Controller in MVC

i have two Html links
and
When i click First Link it goes to Sample controller and goes to advetisement Methode and returns View
public ActionResult advetisement{
// here iam reciveing data to variable
return view()
} now it retuns to view and data is binded and displays Page.Now when i click second link it should go to Same controller(advetisement) and return same Data but view should be diffrent since html styling is changed.
You can load two different views from the same controller action:
if (model.SomeCondition == true)
{
return View("ViewName1", model);
}
return View("ViewName2", model);
Then use your view model to store the condition which determines which view to display:
public class MyViewModel
{
public bool SomeCondition { get; set;}
public object Data { get; set; }
}
I think the easiest way is just having two actions with different names. Of course, code duplication should be extracted to the separate method. Something like this:
public ActionResult Advertisement()
{
return AdvertisementInternal("Advertisement");
}
public ActionResult Advertisement1()
{
return AdvertisementInternal("Advertisement1");
}
private ActionResult AdvertisementInternal(string viewName)
{
// filling ViewBag with your data or creating your view model
...
return View(viewName);
}
But if an appropriate way is the only action for both views then you should have a flag to distinguish the views. It can be added to URL. Something like this:
// on the view
#Html.ActionLink("Link1", "Advertisement", "Sample", new { Id = "View1" }, null)
#Html.ActionLink("Link2", "Advertisement", "Sample", new { Id = "View2" }, null)
// in the controller
public ActionResult Advertisement(string id)
{
if (id == "View1" || id == "View2")
{
// filling ViewBag with your data or creating your view model
...
return View(id);
}
return HttpNotFound();
}

MVC how reload page keeping the data in textbox

(MVC)How to RedirectToAction and keep the content of a Html.Textbox in MVC4? This is my controller how do I fix it and what goes in the view?
[HttpPost]
public ActionResult Index(string ssn)
{
var exist = false;
var record = _db.Citations.Where(u => u.SSN == ssn).FirstOrDefault();
if (record != null)
{
exist = true;
return RedirectToAction("EditDetails", new { id = record.CitationID });
}
else
{
return RedirectToAction("Index", "SubmitAward", ssn); // wiped out ssn! I need to keep the ssn
// so that the user can fill out the form.
}
If your get action is like this:
public ActionResult Index(string ssn)
{
.........
..........
.........
}
then do like this:
return RedirectToAction("Index", "SubmitAward", new { ssn = ssn});
but if it is the same index view of post action which is posted in question, you can pass the object back to view if your view is strongly typed to this class:
return View(record);
Try below code
return RedirectToAction("Index", "SubmitAward", new { ssn = ssn});
And your redirect action will be
public ActionResult Index(string ssn)
{
ViewBag.SSN=ssn;
return View(record);
}
And your view will contain textbox like
#Html.TextBox("SSN",ViewBag.SSN)
It may helps you..

Asp.net mvc what is the best practice of rebuilding ViewModel?

On POST , if validation failed and before sending back the ViewModel to the same View with Model State errors, do you rebuild ViewModel for all SelectLists, ReadOnly fields etc?
right now I have separate methods for Fill First Time(for GET Edit-Method) / Rebuild ViewModels from domain objects, what is the best practice so I can be DRY and also not have to change two methods any time I add a new readonly property to ViewModel?
My Solution: Followed this Pattern
Followed pattern suggested here: https://stackoverflow.com/a/2775656/57132
In IModelBuilder Implementation
Build(..)
{
var viewModel = new ViewModel();
// and Fill all Non-ReadOnly fields
...
...
call CompleteViewModel(viewModel)
}
CompleteViewModel(ViewModel viewModel)
{
//Fill all ReadOnly & SelectLists
...
}
The reason I went with this solution is because I don't want to store stuff on server to retrieve across the HTTP Requests
I don't rebuild it, because I don't stay at POST. I follow POST-REDIRECT-GET pattern, so if I post to /User/Edit/1 using POST HTTP method, I get redirected to /User/Edit/1 uasing GET.
ModelState is transferred to TempData to follow Post-Redirect-Get and be availabe at GET call. View model is built in one place, at GET call. Example:
[HttpPost]
[ExportModelStateToTempData]
public ActionResult Edit(int id, SomeVM postedModel)
{
if (ModelState.IsValid) {
//do something with postedModel and then go back to list
return RedirectToAction(ControllerActions.List);
}
//return back to edit, because there was an error
return RedirectToAction(ControllerActions.Edit, new { id });
}
[ImportModelStateFromTempData]
public ActionResult Edit(int id)
{
var model = //create model here
return View(ControllerActions.Edit, model);
}
This is code for attributes importing/exporting ModelState:
public abstract class ModelStateTempDataTransferAttribute : ActionFilterAttribute
{
protected static readonly string Key = typeof(ModelStateTempDataTransferAttribute).FullName;
}
public class ExportModelStateToTempDataAttribute : ModelStateTempDataTransferAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
//Only export when ModelState is not valid
if (!filterContext.Controller.ViewData.ModelState.IsValid)
{
//Export if we are redirecting
if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult))
{
filterContext.Controller.TempData[Key] = filterContext.Controller.ViewData.ModelState;
}
}
base.OnActionExecuted(filterContext);
}
}
public class ImportModelStateFromTempDataAttribute : ModelStateTempDataTransferAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
ModelStateDictionary modelState = filterContext.Controller.TempData[Key] as ModelStateDictionary;
if (modelState != null)
{
//Only Import if we are viewing
if (filterContext.Result is ViewResult)
{
filterContext.Controller.ViewData.ModelState.Merge(modelState);
}
else
{
//Otherwise remove it.
filterContext.Controller.TempData.Remove(Key);
}
}
base.OnActionExecuted(filterContext);
}
}
The simplest solution would be to pass in you viewModel to the method and account for null
private MyViewModel BuildViewModel(MyViewModel model = null)
{
model = model ?? new MyViewModel();
model.ReadOnlyList = new .....
.
.
return model;
}
for Create:
var model = BuildViewModel();
for rebuild:
model = buildViewModel(model);
I like #LukLed's answer above - it looks very interesting. If you want another option, here's what I currently do.
In my service layer, I have a method to build my view model. I call that on GET and return the the view model to the view. On POST, I build the model from the incoming ID and then TryUpdateModel(model). From there, you can do whatever you like (save, check model state, etc.). With this method, you only have 1 build method and only have to update it once if your model changes (i.e. add/remove properties in the future, etc.).
[HttpGet]
public ActionResult AssessFocuses(int apaID)
{
var model = this.apaService.BuildAssessFocusesViewModel(apaID);
return this.View(model);
}
[HttpPost]
public ActionResult AssessFocuses(int apaID, string button)
{
var model = this.apaService.BuildAssessFocusesViewModel(apaID);
this.TryUpdateModel(model);
switch (button)
{
case ButtonSubmitValues.Back:
case ButtonSubmitValues.Next:
case ButtonSubmitValues.Save:
case ButtonSubmitValues.SaveAndClose:
{
try
{
this.apaService.SaveFocusResults(model);
}
catch (ModelStateException<AssessFocusesViewModel> mse)
{
mse.ApplyTo(this.ModelState);
}
if (!this.ModelState.IsValid)
{
this.ShowErrorMessage(Resources.ErrorMsg_WEB_ValidationSummaryTitle);
return this.View(model);
}
break;
}
default:
throw new InvalidOperationException(string.Format(Resources.ErrorMsg_WEB_InvalidButton, button));
}
switch (button)
{
case ButtonSubmitValues.Back:
return this.RedirectToActionFor<APAController>(c => c.EnterRecommendationsPartner(model.ApaID));
case ButtonSubmitValues.Next:
return this.RedirectToActionFor<APAController>(c => c.AssessCompetenciesPartner(model.ApaID));
case ButtonSubmitValues.Save:
this.ShowSuccessMessage(Resources.Msg_WEB_NotifyBarSuccessGeneral);
return this.RedirectToActionFor<APAController>(c => c.AssessFocuses(model.ApaID));
case ButtonSubmitValues.SaveAndClose:
default:
return this.RedirectToActionFor<UtilityController>(c => c.CloseWindow());
}
}

The model item passed into the dictionary is of type 'System.Data.Objects.ObjectQuery`1

im trying to get the controller in my mvc application to edit a specific entity from a data model once the user clicks on the edit button, however I can't seem to make it work. I keep getting this error
The model item passed into the dictionary is of type 'System.Data.Objects.ObjectQuery`1[MvcApplication1.Models.New]' but this dictionary requires a model item of type 'MvcApplication1.Models.New'.
what am I doin wrong. is it due to the strongly typed view??
here is my controller:
public ActionResult Edit(int id)
{
var productToEdit = from s in _entities.NewSet // return the story matching the clicked id
where s.storyId == id
select s;
return View(productToEdit);
}
// POST : Edit
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(New productToEdit)
{
try
{
var originalNews = (from s in _entities.NewSet
where s.storyId == productToEdit.storyId
select s).FirstOrDefault();
_entities.ApplyPropertyChanges(originalNews.EntityKey.EntitySetName, productToEdit);
_entities.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
can someone give me a few pointers please. Im still new to all of this.
Change your Edit action with Int Parameter to as follows:
public ActionResult Edit(int id)
{
var productToEdit = from s in _entities.NewSet
where s.storyId == id
select s;
return View(productToEdit.FirstOrDefault());
}

Resources