How to redirect to Details View? - asp.net-mvc-3

This is my LearnController and here is the create.
[HttpPost]
public ActionResult Create(Learn learn)
{
if (ModelState.IsValid)
{
db.Learns.Add(learn);
db.SaveChanges();
return RedirectToAction("Details", new { id = learn.ModuleId });
}
ViewBag.ModuleId = new SelectList(db.Modules, "ModuleId", "Code", learn.ModuleId);
return View(learn);
}
Here is the detail in my LearnController
public ViewResult Details(int id)
{
var mod = db.Modules.Include("Learns").Single(g => g.ModuleId == id);
return View(mod);
}
In my create view of the learning controller, I place a HTMLActionLink but I can't seem to be redirected. Is there something wrong with my codes?
#Html.ActionLink("Back to List", "Details")
This is the error.
The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ViewResult Details(Int32)' in 'Module1.Controllers.LearnController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters

The link would need to be #Html.ActionLink("Back to List", "Details", new { id = # }) where # is the id of the Module to display. So when you create a new Learn the GET method would need to be something like
public ActionResult Create(int ID) // ID is the ModuleId your creating the Learn for
{
Learn model = new Learn();
model.ModuleID = ID;
return View(model);
}
and in the view
#model Learn
....
#Html.ActionLink("Back to List", "Details", new { id = Model.ModuleID })
This is assuming that the Details view contains a link to create a new Learn for the Module, where the link would be #Html.ActionLink("Add new Learn", "Create", new { id = Model.ID})
If you can create a new Learn from some other view (where you don't have access to the ID property of Module), and where the view to create a new Learn allows you to select the Module form a drop down list, then you would need javascript/jquery to update the href value of the link based on the selected Module

"The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32", the parameters should be nullable type, change to this
public ViewResult Details(int? id)
{
try
{
if (id.HasValue)
{
var mod = db.Modules.Include("Learns").Single(g => g.ModuleId == id);
if (mod == null)
throw new ArgumentException("Invalid ID");
return View(mod);
}
else
{
throw new ArgumentException("Invalid ID");
}
}
catch (ArgumentException ex)
{
return View(new Modules()); // assumed Details view model is Modules class
}
catch
{
return View(new Modules()); // assumed Details view model is Modules class
}
}
or
public ViewResult Details(string id)
{
try
{
int intId;
if(int.TryParse(id, out intId))
{
var mod = db.Modules.Include("Learns").Single(g => g.ModuleId == intId);
if (mod == null) throw new ArgumentException("Invalid ID");
return View(mod);
}
else
{
throw new ArgumentException("Invalid ID");
}
}
catch (ArgumentException ex)
{
return View(new Modules()); // assumed Details view model is Modules class
}
catch
{
return View(new Modules()); // assumed Details view model is Modules class
}
}
Update
I think I misunderstood your question, all you need to do is change
#Html.ActionLink("Back to List", "Details" })
to
#Html.ActionLink("Back to List", "Details", new { id = Model.ModuleId })
as suggested by Stephen Muecke

Related

DropDownList doesn't pass additional parameter

I would like to pass a number selected from DropDownlist to a GET Create method in other Controller. It looks like:
[HttpGet]
public ActionResult Details(int? id, string error)
{
{...}
var numbers = Enumerable.Range(1, 100);
ViewBag.Quantity = numbers.Select(i => new SelectListItem { Value = i.ToString(), Text = i + "%" });
return View(viewModel);
}
public ActionResult Create(int ID, int quantity)
{
{...}
}
Details View looks like:
<div>
#if (Model.ItemRent.Zatwierdzony == false)
{
using (Html.BeginForm("Create", "ItemRentLists", new { ID = #Model.ItemRent.ItemRentID }, FormMethod.Get))
{
#Html.DropDownList("quantity", new SelectList(ViewBag.Quantity, "Text", "Value"))
<input type="submit" value="Dodaj przedmioty"/>
}
}
</div>
DropDownList doesn't pass a Value to "quantity" parameter in Create method, what is wrong here?
OK I changed #Html.DropDownList("quantity", ViewBag.Quantity as SelectList) and now it works as it should work.

MVC3 Areas routing conflict

Question: i want my route to be like that
/admin/main/category/1 -> 1 == ?page=1
i don't want page=1 to be seen
My Controller
public class MainController : BaseController
{
private const int PageSize = 5; //pager view size
[Inject]
public ICategoryRepository CategoryRepository { get; set; }
public ActionResult Index()
{
return View();
}
public ActionResult Category(int page)
{
//int pageIndex = page.HasValue ? page.Value : 1;
int pageIndex = page != 0 ? page : 1;
return View("Category", CategoryViewModelFactory(pageIndex));
}
/*
*Helper: private instance/static methods
======================================================================*/
private CategoryViewModel CategoryViewModelFactory(int pageIndex) //generate viewmodel category result on pager request
{
return new CategoryViewModel
{
Categories = CategoryRepository.GetActiveCategoriesListDescending().ToPagedList(pageIndex, PageSize)
};
}
}
public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "admin";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRouteLowercase(
"AdminCategoryListView",
"admin/{controller}/{action}/{page}",
new { controller = "Category", action = "Category", page = "1" },
new { id = #"\d+" },
new[] { "WebUI.Areas.Admin.Controllers" }
);
}
}
My Exception:
The parameters dictionary contains a null entry for parameter 'page'
of non-nullable type 'System.Int32' for method
'System.Web.Mvc.ActionResult Category(Int32)' in
'WebUI.Areas.Admin.Controllers.MainController'. An optional parameter
must be a reference type, a nullable type, or be declared as an
optional parameter. Parameter name: parameters
Thank you all in advance.
Make sure that in your Admin area route registration you have defined the {page} route token instead of {id} which is generated by default:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{page}",
new { action = "Index", page = UrlParameter.Optional }
);
}
Now when you are generating links make sure you specify this parameter:
#Html.ActionLink(
"go to page 5", // linkText
"category", // actionName
"main", // controllerName
new { area = "admin", page = "5" }, // routeValues
null // htmlAttributes
)
will emit:
go to page 5
and when this url is requested the Category action will be invoked and passed page=5 parameter.

Storing ActionLink in model or RouteValueDictionary in model

I wish to store an action link in the model.
Something like
public MvcHtmlString ActionLink_New
{
get { return Html.ActionLink("new", "Edit", "News", new { Area = "Admin" }, null); }
}
It appears the model needs a webviewpage context.
Failing that, I thought I would store just the route values.
public RouteValueDictionary[] RouteValue_New
{
get { return new RouteValueDictionary[] { Area = "Admin" }; }
}
//View
#Html.ActionLink("new", "Edit", "News", Model.RouteValue_New, null)
The Area in the property is red. Is either or both scenario achievable. What do i need to add to get this to work, thanks.
try this
public object RouteValue_New
{
get {
return new { Area = "Admin" };
}
}

Orchard CMS rendering parts outside of admin section

I am working on a module by following the instructions here http://orchardproject.net/docs/Creating-a-module-with-a-simple-text-editor.ashx
The one change I want to do is, rendering the product creation outside of admin module. So I created homecontroller like this
public class HomeController : Controller
{
public HomeController(IContentManager cm) {
ContentManager = cm;
}
private IContentManager ContentManager { get; set; }
public ActionResult Index() {
return Content("This is index");
} [Themed]
public ActionResult Create()
{
var product = ContentManager.New("Product");
var model = ContentManager.BuildEditor(product);
return View((object) model);
}
and a file routes.cs in the root folder
public class Routes : IRouteProvider
{
public void GetRoutes(ICollection<RouteDescriptor> routes)
{
foreach (var routeDescriptor in GetRoutes())
routes.Add(routeDescriptor);
}
public IEnumerable<RouteDescriptor> GetRoutes()
{
return new[] {
new RouteDescriptor {
Priority = 5,
Route = new Route(
"commerce",
new RouteValueDictionary {
{"area", "SimpleCommerce"},
{"controller", "Home"},
{"action", "Index"}
},
new RouteValueDictionary(),
new RouteValueDictionary {
{"area", "SimpleCommerce"}
},
new MvcRouteHandler())
},
new RouteDescriptor {
Priority = 6,
Route = new Route(
"commerce/Create",
new RouteValueDictionary {
{"area", "SimpleCommerce"},
{"controller", "Home"},
{"action", "Create"}
},
new RouteValueDictionary(),
new RouteValueDictionary {
{"area", "SimpleCommerce"}
},
new MvcRouteHandler())
}
};
}
}
So how should I move from here onwards to render this whole thing together when I navigate to url http://localhost:35713/commerce/create
But it throws an error saying create view didnt find. Then I created a view (create.cshtml) in Views/Home folder
#model SimpleCommerce.Models.ProductPart
<fieldset>
<label class="sub" for="Sku">#T("Sku")</label><br />
#Html.TextBoxFor(m => m.Sku, new { #class = "text" })<br />
<label class="sub" for="Price">#T("Price")</label><br />
#Html.TextBoxFor(m => m.Price, new { #class = "text" })
</fieldset>
Now it throws an error saying
The model item passed into the dictionary is of type 'IShapeProxyedcfa08c61cf49898dc2e77bde025039', but this dictionary requires a model item of type 'SimpleCommerce.Models.ProductPart'.
Oh, that's cross-posted. BuildEditor is creating a shape, and your template is expecting a strongly-typed model. Dropping the #Model directive should substitute that problem with another (which is that you won't be able to use the Lambda-based helpers with shapes.

ModelsState always invalid when using Html.DropDownListFor

This is how I create my dropdown
#Html.DropDownListFor(model => model.NewPageModel.AvailablePageModels, new SelectList(Model.NewPageModel.AvailablePageModels, "Text", "Value"))
and this is how my AvailablePageModels looks like
public IEnumerable<SelectListItem> AvailablePageModels
{
get
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in assembly.GetTypes())
{
if (type.GetCustomAttributes(typeof(PageModelAttribute), true).Length > 0)
{
yield return new SelectListItem { Text = type.Name, Value = type.Name };
}
}
}
}
}
and when I post my form to the following action my modelstate is always invalid and the error occur on the AvailablePageModel value? Maybe I cannot use the NewPageModel as a parameter this way?
public ActionResult Create([Bind(Prefix = "NewPageModel")] NewPageModel newPageModel, FormCollection collection)
{
if(ModelState.IsValid) {
// always invalid
}
}
You need 2 fields, one for the available options in the drop down list and one for storing the selected value
Html.DropDownListFor(m => m.NewPageModel.SelectedModel,
new SelectList(Model.NewPageModel.AvailablePageModels, "Text", "Value"))

Resources