how to handle hange my routes value? - asp.net-mvc-3

i have an area and change my route to this
public class WeblogsAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Weblogs";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Weblogs_default",
"Weblogs/{controller}/{action}/{blogName}/{post}",
new { action = "Index",
blogName = UrlParameter.Optional,post=UrlParameter.Optional}
);
}
}
and it is my index
public ActionResult Index(string blogName,int post)
{
return View();
}
it works fine by this:
http://localhost:2927/Weblogs/Blogs?blogName=Myco&Post=3
but works not by
http://localhost:2927/Weblogs/Blogs?blogName=Myco
what is the problem?
how can i change my rout to works with this URL:
http://localhost:2927/Weblogs/Blogs/Myco/3
"myco" is blog name and 3 is post number.
is it possible?

Remove your action and controller tokens from your route. Modify it to be like so:
context.MapRoute(
"Weblogs_default",
"Weblogs/Blogs/{blogName}/{post}",
new { action = "Index",
Controller = "Blogs",
blogName = UrlParameter.Optional,
post=UrlParameter.Optional}
);

Related

Unit Test ASP MVC Route with Constraint

I have a route that is defined like this:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional, area = "" }, // Parameter defaults
new { home = new HomePageConstraint() }
);
public class HomePageConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return !httpContext.Request.RawUrl.StartsWith("/home", StringComparison.InvariantCultureIgnoreCase);
}
}
And I am trying to test it like this:
[Test]
public void Home_Load_Homepage()
{
"~/".ShouldMapTo<HomeController>(x => x.Index());
}
The problem I have is that the httpContext is null, so the test fails. how can I inject http context into a constraint?
In the end I did this:
var context = new FakeHttpContext("~/");
var fakeRequest = new FakeRequest("~/", new Uri("http://localhost/"), new Uri("http://localhost/"));
context.SetRequest(fakeRequest);
var route = RouteTable.Routes.GetRouteData(context);
route.ShouldMapTo<HomeController>(x => x.Index());

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.

hypen in MVC 3 routes

Here is my desired url format: /product-24-hid-35wh4-cx-dsgtx
How can I map this URL to my action method:
public ActionResult Product(int id)
Here is my routing code:
routes.MapRoute(
"ProductDetail",
"product-{id}-{name}",
new { controller = "product", action = "detail", name = UrlParameter.Optional },
new string[] { "SphereLight.Controllers" }
);
However, it does not work; I used phil haack's routedebugger to test this route, and below is the result:
Key Value
name dsgtx
id 24-hid-35wh4-cx
controller product
action detail
Only id = 24 is correct.
In one word, I need a route to match:
/product-24
/product-24-
/product-24-hid-35wh4-cx-dsgtx
Try to add constraints in your MapRoute:
routes.MapRoute(
"ProductDetail",
"product-{id}-{name}",
new { controller = "product", action = "detail", name = UrlParameter.Optional },
new { id = #"\d+" }, // <-- change it for #"[^-]+", if it can be non-digit
new string[] { "SphereLight.Controllers" }
);
UPDATE:
Finally got it.
The main problem is that you can't use parameters which contains the same separator.
For example, the example above will work with /product-24-nm, but not with product-24-nm-smth.
So, let's try this solution:
I've made it on the default routing, you can make it your way
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new MyRouteHandler()
).RouteHandler = new MyRouteHandler();
Implementation of MyRouteHandler:
public class MyRouteHandler : MvcRouteHandler
{
private static readonly Regex ProductPattern = new Regex(#"product\-(\d+)\-?(.*)");
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var match = ProductPattern.Match(requestContext.RouteData.Values["controller"].ToString());
if (match.Length > 0)
{
requestContext.RouteData.Values["controller"] = "Home";
requestContext.RouteData.Values["action"] = "Detail";
requestContext.RouteData.Values["id"] = match.Groups[1].Value;
requestContext.RouteData.Values["name"] = match.Groups[2].Value;
}
return base.GetHttpHandler(requestContext);
}
}
So, the main idea is to check if the values matches our pattern product-id-name in the handler, and not trying to make it in MapRoute.
Hope this helps.

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.

Resources