Spark View Engine & Areas in ASP.NET MVC 2 - spark-view-engine

Anyone got the areaDescriptorFilter working with the spark view engine in asp.net mvc 2?
I don't even have the option to add a filter on the service as shown in the following:
http://sparkviewengine.com/documentation/viewlocations#Extendingfilepatternswithdescriptorfilters
Thanks if you can help or at least try.

I'm using areas with Spark in a project of mine. All I had to do was add AreaRegistration classes for each area like:
public class AdminAreaRegistration : System.Web.Mvc.AreaRegistration
{
public override string AreaName
{
get { return "Admin"; }
}
public override void RegisterArea( AreaRegistrationContext context )
{
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
and then in the global.asax call:
AreaRegistration.RegisterAllAreas();
I have my area views located in a folder named "Admin" under the default "Views" folder, with appropriate controller folders under that:
\MvcProject
\Views
\Admin
\Home
\Index.spark
\Users
\Index.spark
from the page you linked:
the AreaDescriptorFilter is added by default
so you shouldn't need to worry about adding it yourself.

Related

Whats wrong with my routes and actions?

I recently asked a question based on how to create pages based on the content table which contains the following: Title and Content. I followed the steps, to my understanding, in the answer that was given.
I created a route like so:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"ContentManagement",
"{title}",
new { controller = "ContentManagement", action = "Index", title = "{title}" }
);
}
I am assuming I can do routes like this? where I can set up multiple routes? I am also assuming I can pass the title to to the controller action like I have done?
I then created the model:
namespace LocApp.Models
{
public class ContentManagement
{
public int id { get; set; }
[Required]
public string title { get; set; }
public string content { get; set; }
}
}
from that I created a controller with an index action that looks as such:
public ViewResult Index(string title)
{
using (var db = new LocAppContext())
{
var content = (from c in db.Contents
where c.title == title
select c).ToList();
return View(content);
}
}
So then I created some content with the title of "bla" so when I visit site.com/bla I get an error that it cant find "bla/"
Can some one tell me what I am doing wrong? I would also, if you are familiar with the default layout of a asp.net mvc project with the tabs at the top, create a set of tabs that lead to the pages, based on the title in the database
The main issue is that when you are using the title, the routing engine is matching it to the first route and trying to find a controller by that title. We have implemented something similar and found that by explicitly defining what controllers are valid for the default route, it then processed request appropriately. I gave an example of the controllers that we allow to fit our default route below (Home, Help and Error).
You probably also want to prevent people from giving the content the same TITLE as your root level controllers as that would blow this up pretty well.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new {controller = "Home", action = "Index", id = UrlParameter.Optional},
new {controller = "Home|Error|Help"},
new[] {"UI_WWW.Controllers"});
routes.MapRoute(
"ContentManagement",
"{title}",
new {controller = "ContentManagement", action = "Index"});
}
}

Sitecore context not loaded in custom controller

I followed this tutorial, and created this code:
using Glass.Sitecore.Mapper;
using Sitecore.Mvc.Controllers;
using Sitecore.SecurityModel;
using SitecoreCMSMVCBase.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace SitecoreCMSMVCBase.Controllers
{
public class CommentController : SitecoreController
{
ISitecoreContext _context;
ISitecoreService _master;
public CommentController()
: this(
new SitecoreContext(),
new SitecoreService("master"))
{
}
/// <summary>
/// This constructor can be used with dependency injection or unit testing
/// </summary>
public CommentController(ISitecoreContext context, ISitecoreService master)
{
_context = context;
_master = master;
}
[HttpGet]
public override ActionResult Index()
{
var model = _context.GetCurrentItem<CommentPage>();
return View(model);
}
[HttpPost]
public ActionResult Index(Comment comment)
{
var webModel = _context.GetCurrentItem<CommentPage>();
if (ModelState.IsValid)
{
var masterModel = _master.GetItem<CommentPage>(webModel.Id);
if (masterModel.CommentFolder == null)
{
CommentFolder folder = new CommentFolder();
folder.Name = "Comments";
using (new SecurityDisabler())
{
_context.Create(masterModel, folder);
}
masterModel.CommentFolder = folder;
}
using (new SecurityDisabler())
{
comment.Name = DateTime.Now.ToString("yyyyMMddhhmmss");
//create the comment in the master database
_master.Create(masterModel.CommentFolder, comment);
webModel.CommentAdded = true;
}
}
return View(webModel);
}
}
}
Models are identical with tutorial, so I will not paste them.
My route configuration looks like this:
routes.MapRoute(
"CommentController", // Route name
"Comment/{action}/{id}", // URL with parameters
new { controller = "Comment", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
When I navigate to /comment I see this exception:
Glass.Sitecore.Mapper.MapperException: Context has not been loaded
I tried with commenting my route specification (as there was nothing about routes in tutorial), and then error is different (throwing by Sitecore CMS itself):
The requested document was not found
Do you know how to load Sitecore context into custom Controller, and make this simple example work? I was looking everywhere but couldn't find any good answer...
I think this is more a Glass setup issue, rather than an MVC routing problem.
To setup Glass, you need to initialise the context in your application start method in your Global.asax file.
var loader = new Glass.Sitecore.Mapper.Configuration.Attributes.AttributeConfigurationLoader(
"Glass.Sitecore.Mapper.Tutorial.Models, Glass.Sitecore.Mapper.Tutorial");
Glass.Sitecore.Mapper.Context context = new Context(loader);
For other Glass-setup related stuff I recommend following the first tutorial on the glass.lu website.
http://www.glass.lu/tutorials/glass-sitecore-mapper-tutorials/tutorial-1-setup/
This method doesn't need Glass at all!
First step is to set your route in Global.asax file.
routes.MapRoute(
"DemoController", // Route name
"Demo/{action}/{param}", // URL with parameters
new { controller = "Demo", action = "Index", param = "", scItemPath = "/sitecore/content/DemoHomePage" } // Parameter defaults
);
Notice that controller is not taken as parameter, but is fixed, to prevent handling it by Sitecore. More info here and here. Notice that there is one additional parameter - scItemPath. It contains path to item which by default will be included in page context.
Having this route our traffic from /demo is handled by DemoController and Index action. Inside this action all you need is to add is this line:
Sitecore.Data.Items.Item item = Sitecore.Mvc.Presentation.PageContext.Current.Item;
item variable will contain your Sitecore item pointed by scItemPath.
And that's all - it should work well now - hope it helps!

ServiceRoute in ASP.NET MVC with areas intercepts ActionLink to Home

I have an MVC 3 application with areas, and I am exposing a service from a specific area and controller. The routing to this service is defined inside the AreaRegistration like this
public class AreaAreaRegistration : AreaRegistration
{
public override string AreaName
{
get { return "Area"; }
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.Routes.Add(
new ServiceRoute("Area/Controller/Service",
new NinjectServiceHostFactory(), typeof(MyService)));
// ....
}
}
In my Global.asax.cs I only define a default route
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
In my _Layout.chshtml I have a link to my home page, where I give an empty area, and I expect it to find the Index action in the HomeController in the Controllers folder at the top (outside the Areas folder):
#Html.ActionLink("Home", "Index", "Home", new { area = "" }, null)
For some reason this ActionLink renders as
~/Area/Controller/Service?action=Index&controller=Home
If I comment out the ServiceRoute, the same ActionLink points to ~/ which is what I expect.
Any ideas how to fix this routing issue? The only workaround I have found is to use this instead:
Home
We were having this exact same problem. The order of route registration appears to be the issue, in that routes from areas will be registered before routes from the global.asax code.
To fix this issue, allowing the URL route to the service as well as preventing the postback from being targeted at the service URL try moving the ServiceRoute addition into the Global.asax.cs after the other route is registered.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
context.Routes.Add(
new ServiceRoute("Area/Controller/Service",
new NinjectServiceHostFactory(), typeof(MyService)));
}
This worked for us, but does of course come at the overhead of putting code pertaining to the area in the main project.

ASP.NET MVC Areas routing not working with default route

I am trying to separate my MVC project into multiple areas. So i have 3 areas 1) crm 2)services 3) Web. I want PublicWeb to be my default one. that means it should be accessed like www.mysitename.com/mycontroller/myaction( no area name inbetween) and other two to be accessed with the area name (www.mysitename.com/crm/mycontroller/myaction). What routing/ Area configuration i should have ? I tried AreaRegistration.RegisterAllAreas(); and it works only for my default one (web). When i access the other 2, it threw 404 error.
I tried to register indidually like the below one
var area2reg = new crmAreaRegistration();
var area2context = new AreaRegistrationContext(area2reg.AreaName, RouteTable.Routes);
area2reg.RegisterArea(area2context);
var area1reg = new webAreaRegistration();
var area1context = new AreaRegistrationContext(area1reg.AreaName, RouteTable.Routes);
area1reg.RegisterArea(area1context);
Then my publicweb works. But when i access my forum it threw this error,
Multiple types were found that match the controller named 'home'. This can happen if the route that services this request ('crm/{controller}/{action}/{id}') does not specify namespaces to search for a controller that matches the request. If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter.
My RegisterArea function for web is this
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"web_default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
and the one for crm is this
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"crm_default",
"crm/{controller}/{action}/{id}",
new { controller = "home", action = "Index", id = UrlParameter.Optional }
);
}
}
How do i handle this ?
From what I can see the area routes look fine. Did you update the default route in your Global.asax to send requests to the web area?
Something like:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}",
new { area = "web", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
I think Jonathan S's solution is definitely worth a try, but you might consider a different approach. That would be to put your web files in the default locations. The routing engine would not look in the Area's for those files when no Area is part of the request.

asp.net mvc dynamic area selection based on route parameter value

I am working on an application surrounding sporting events. There are different types of events like a soccer tournament and a tennis tournament. Based on the type of tournament I want to have the requests proccessed by a different area. But the events and their tournament type is something that is configurable by users of the application and stored in the database.
Currrently I have this proof of concept:
public class SoccerTournamentAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "SoccerTournament";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
var soccerTournaments = new string[] { "championsleague", "worldcup" };
foreach (var tournament in soccerTournaments)
{
context.MapRoute(
string.Format("SoccerTournament_default{0}", tournament),
string.Format("{0}/{{controller}}/{{action}}/{{id}}", tournament),
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new[] { "Mvc3AreaTest1.Areas.SoccerTournament.Controllers" }
);
}
}
}
and it works only I want soccerTournaments to come from the database (not a problem) but I also want it to work ask soon as a new event/tournament type record is added to the database and that doesn't work in this case.
How can I make the area selection dynamic instead of hard coded into routes?
Area registration only occurs at the application start, so any tournaments added after startup will not be captured until a re-start.
To have a dynamic routing scheme for your tournaments, you must redefine your area route and add a RouteConstraint.
Redefine your route as follows:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"SoccerTournament_default",
"{tournament}/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { tournament = new MustBeTournamentName() },
new string[] { "Mvc3AreaTest1.Areas.SoccerTournament.Controllers" }
);
}
Than, you can create the MustBeTournamentName RouteConstraint to be similar to the RouteConstraint in the answer to this question: Asp.Net Custom Routing and custom routing and add category before controller

Resources