I just barely created a new Area to organize my code.
But currently I am having trouble actually linking it from my "base" or "root" index page, to my new area page.
#Html.ActionLink("Tube Record Form", "BearingAssemblyForm", "_HiCT", new { area = "HICT" }, null)
public class HICTAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "HICT";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"HICT_default",
"HICT/{controller}/{action}/{id}",
new {controller = "_HiCT", action = "BearingAssemblyForm", id = UrlParameter.Optional }
);
}
}
The resource cannot be found.
And it seems its linked wrongly
Requested URL: /HICT/HiCT/BearingAssemblyForm
Controller: HiCT,
View/Action: BearingAssemblyForm, Area: HICT.
How would I like this?
Thank you so much.
Try this:
#Html.ActionLink("LinkText",
"ActionName",
"ControllerName",
new { area = "HICT" }, null)
I think you're not using the correct #Html.ActionLink method overload.
First off all, see if your area is registered correctly:
public class Routes : AreaRegistration
{
public override string AreaName
{
get
{
return "HICT";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"HICT_default",
"HICT/{controller}/{action}/{id}",
new { controller = "_HiCT", action = "BearingAssemblyForm", id = UrlParameter.Optional }
);
}
Make sure you're calling RegisterAllAreas inside the Global.asax.cs file:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
...
}
/Master/BearingAssemblyForm
usually, Master is the controller and the 2nd part is action, so it seems your controller name is different than your route.
Its been a wile but this should work.
#Html.ActionLink("Tube Record Form", "action", "Area/controller")
Are you calling:
AreaRegistration.RegisterAllAreas();
on Application_Start in your Global.asax? What server are you using for development Cassini, IISExpress, IIS?
Edit after reviewing more detailed information.
In your Admin Area Registration File if you have this code
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new string[] { "CoolProject.Web.Areas.Admin.Contollers" }
);
I think there is a typo in CoolProject.Web.Areas.Admin.Contollers and it should be CoolProject.Web.Areas.Admin.Controllers?
Related
I would like to be able to create a succinct language-specific default URL for my website so that when someone browses to:
somesite.com
They get redirected to a language-culture page such as:
somesite.com/en-US/
somesite.com/sp-MX/
somesite.com/fr-FR/
Specifically, I do not want /Home/Index appended to the URLs:
somesite.com/en-US/Home/Index
somesite.com/sp-MX/Home/Index
somesite.com/fr-FR/Home/Index
I am committed to making this site using RouteLocalization.mvc
Dresel/RouteLocalization
Translating Your ASP.NET MVC Routes
And I would like to use MVC Attribute Routing to the extent feasible.
I am having trouble figuring out how to cause the Start() method redirect to a language-culture specific URL without the addition of something like "index".
Samples of what I have attempted follow:
using RouteLocalization.Mvc;
using RouteLocalization.Mvc.Extensions;
using RouteLocalization.Mvc.Setup;
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.Clear();
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes(Localization.LocalizationDirectRouteProvider);
const string en = "en-us";
ISet<string> acceptedCultures = new HashSet<string>() { en, "de", "fr", "es", "it" };
routes.Localization(configuration =>
{
configuration.DefaultCulture = en;
configuration.AcceptedCultures = acceptedCultures;
configuration.AttributeRouteProcessing = AttributeRouteProcessing.AddAsNeutralAndDefaultCultureRoute;
configuration.AddCultureAsRoutePrefix = true;
configuration.AddTranslationToSimiliarUrls = true;
}).TranslateInitialAttributeRoutes().Translate(localization =>
{
localization.AddRoutesTranslation();
});
CultureSensitiveHttpModule.GetCultureFromHttpContextDelegate = Localization.DetectCultureFromBrowserUserLanguages(acceptedCultures, en);
var defaultCulture = System.Threading.Thread.CurrentThread.CurrentUICulture.Name;
routes.MapRoute(
name: "DefaultLocalized",
url: "{culture}/{controller}/{action}/{id}",
constraints: new { culture = #"(\w{2})|(\w{2}-\w{2})" },
defaults: new { culture = defaultCulture, controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
And my home controller:
public class HomeController : Controller
{
[HttpGet]
[Route]
public RedirectToRouteResult Start()
{
return RedirectToAction("Home", new { culture = Thread.CurrentThread.CurrentCulture.Name });
}
[Route("Index", Name = "Home.Index")]
public ActionResult Index()
{
return View();
}
public ActionResult Contact()
{
return View();
}
public ActionResult About()
{
return View();
}
}
My Global.asax file:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
AreaRegistration.RegisterAllAreas();
}
}
Redirecting is a separate concern than routing. Since your goal of redirecting any URL to its localized counterpart is a cross-cutting concern your best bet is to make a global filter.
public class RedirectToUserLanguageFilter : IActionFilter
{
private readonly string defaultCulture;
private readonly IEnumerable<string> supportedCultures;
public RedirectToUserLanguageFilter(string defaultCulture, IEnumerable<string> supportedCultures)
{
if (string.IsNullOrEmpty(defaultCulture))
throw new ArgumentNullException("defaultCulture");
if (supportedCultures == null || !supportedCultures.Any())
throw new ArgumentNullException("supportedCultures");
this.defaultCulture = defaultCulture;
this.supportedCultures = supportedCultures;
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
var routeValues = filterContext.RequestContext.RouteData.Values;
// If there is no value for culture, redirect
if (routeValues != null && !routeValues.ContainsKey("culture"))
{
string culture = this.defaultCulture;
var userLanguages = filterContext.HttpContext.Request.UserLanguages;
if (userLanguages.Length > 0)
{
foreach (string language in userLanguages.SelectMany(x => x.Split(';')))
{
// Check whether language is supported before setting it.
if (supportedCultures.Contains(language))
{
culture = language;
break;
}
}
}
// Add the culture to the route values
routeValues.Add("culture", culture);
filterContext.Result = new RedirectToRouteResult(routeValues);
}
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
// Do nothing
}
}
Usage
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new RedirectToUserLanguageFilter("en", new string[] { "en", "de", "fr", "es", "it" }));
filters.Add(new HandleErrorAttribute());
}
}
Note also that your routing is misconfigured. The route setup is run one time per application startup, so setting the default culture to that of the current thread is meaningless. In fact, you should not be setting a default culture at all for your culture route because you want it to miss so your Default route will execute if there is no culture set.
routes.MapRoute(
name: "DefaultLocalized",
url: "{culture}/{controller}/{action}/{id}",
constraints: new { culture = #"(\w{2})|(\w{2}-\w{2})" },
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
At this moment, I am register at AreaRegistraion as below:-
public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get { return "Admin"; }
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"custom_admin_order",
"Admin/Order/List/",
new { controller = "CustomOrder", action = "List", area = "Admin", id = "" },
new[] { "Misc.CustomAdminOrder.Controllers" });
}
}
It is working, but sometime doesn't work and need to restart the application and clear cache several times to make it work.
So right now I need a better way to make it 100% work.
I have 2 areas in my project:
Areas | Admin
Areas | FrontEnd
What I would like is when I visit the site, the default route should load Controllers / Views / Models from the FrontEnd area. It's normal to have Url/Admin for an admin panel but I would rather not have to force Url/FrontEnd (or some other variation). Basically I don't want to use the Controller / Model / View folders on the root level.
I'm not sure how to change the code to allow this or even it's an advisable method. Could someone provide some guidance please?
What I have:
routes.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new {
area = "Admin",
controller = "Home",
action = "Index",
id = UrlParameter.Optional
},
namespaces: new[] { "WebsiteEngine.Areas.Admin.Controllers" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new {
area = "FrontEnd",
controller = "Home",
action = "Index",
id = UrlParameter.Optional
},
namespaces: new[] { "WebsiteEngine.Areas.FrontEnd.Controllers" }
);
However this produces an error:
The view 'Index' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/Home/Index.aspx
~/Views/Home/Index.ascx
~/Views/Shared/Index.aspx
~/Views/Shared/Index.ascx
~/Views/Home/Index.cshtml
~/Views/Home/Index.vbhtml
~/Views/Shared/Index.cshtml
~/Views/Shared/Index.vbhtml
I do have views available in the areas and this doesn't look like it's looking there.
I believe you can just do something like this:
// Areas/Admin/AdminAreaRegistration.cs
public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get { return "Admin"; }
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
name: "Admin_Default",
url: "Admin/{controller}/{action}/{id}",
defaults: new
{
area = "Admin",
controller = "Home",
action = "Index",
id = UrlParameter.Optional
});
}
}
// Areas/Admin/FrontEndAreaRegistration.cs
public class FrontEndAreaRegistration : AreaRegistration
{
public override string AreaName
{
get { return "FrontEnd"; }
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
name: "FrontEnd_Default",
url: "{controller}/{action}/{id}",
defaults: new
{
area = "FrontEnd",
controller = "Home",
action = "Index",
id = UrlParameter.Optional
});
}
}
// Global.asax.cs
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
...
}
Now, in your RouteConfig class, you probably have a Default route set up. Bear in mind that as long as you call AreaRegistration.RegisterAllAreas before you call RouteConfig.RegisterRoutes, the routes that you set up in the areas may override the routes you set up in RouteConfig. (Routes are evaluated in the order they appear in the Routes collection, and .MapRoute pushes new routes to the end)
I am getting the above when I try and open a view in a controller in an Area. Ninject is set up as follows:
public class NinjectControllerFactory : DefaultControllerFactory
{
private IKernel kernel = new StandardKernel(new RLSBCWebSiteServices());
protected override IController GetControllerInstance(RequestContext context, Type controllerType)
{
if (controllerType == null)
return null;
return (IController)kernel.Get(controllerType);
}
private class MyWebSiteServices : NinjectModule
{
public override void Load()
{
Bind<IMatchesRepository>().To<SqlMatchesRepository>().WithConstructorArgument("connectionString",
ConfigurationManager.ConnectionStrings["MyWebSiteDb"].ConnectionString);
}
}
}
If I place a breakpoint in the code, I see the RequestContext context contains the following values:
context.RouteData.DataTokens.Values[0] = “MyWebSite.WebUI.Areas.Visitor” context.RouteData.DataTokens.Values[1] = “Visitor” which is the Area
context.RouteData.Values.Values[0] = “admin” which is the Controller
context.RouteData.Values.Values[1] = “register” which is the View
However controllerType == null, instead on the controller name.
This transfer to the new page is being triggered by
Html.ActionLink("here", "Register", "Admin", new { area = "Visitor" }, null)
which is on the Login page. However the same thing happens if I enter
http://example.com/Visitor/admin/register
into IE8
The area registration is as follows:
public class VisitorAreaRegistration : AreaRegistration
{
public override string AreaName { get { return "Visitor"; } }
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Visitor_default",
"Visitor/{controller}/{action}/{id}",
new { controller = "Admin", action = "Register", id = UrlParameter.Optional }
);
}
}
Has anyone managed to get Areas working with NinjectControllerFactory, or is there something wrong with my set-up?
Instead of creating your own NinjectControllerFactory use the latest version of Ninject.Web.Mvc. It supports Areas. See: https://github.com/ninject/ninject.web.mvc
Check your controller and action name in view. I also got same error as an action name was wrong.
Using ASP.NET MVC, I need to configure my URLs like this:
www.foo.com/company : render View Company
www.foo.com/company/about : render View Company
www.foo.com/company/about/mission : render View Mission
If "company" is my controller and "about" is my action, what should be "mission"?
For every "folder" (company, about and mission) I have to render a different View.
Anyone knows how can I do that?
Thanks!
First, setup your views:
Views\
Company\
Index.aspx
About.aspx
Mission.aspx
AnotherAction.aspx
In your GlobalAsax.RegisterRoutes(RouteCollection routes) method:
public static void RegisterRoutes(RouteCollection routes)
{
// this will match urls starting with company/about, and then will call the particular
// action (if it exists)
routes.MapRoute("mission", "company/about/{action}",
new { controller = "Company"});
// the default route goes at the end...
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
In the controller:
CompanyController
{
public ViewResult Index() { return View(); }
public ViewResult About() { return View(); }
public ViewResult Mission() { return View(); }
public ViewResult AnotherAction() { return View(); }
}