I have an MVC5 application using ASP Identity 2 and Fluentsecurity with the following methods in the Home controller which handle the log in page and logging out:
public ActionResult Login(string returnUrl)
{
this.ViewBag.ReturnUrl = returnUrl;
return this.View();
}
public ActionResult LogOff()
{
this.AuthenticationManager.SignOut();
return this.RedirectToAction("Login", "Home");
}
This works absolutely fine.
I now need to add an area into my application and set up routing accordingly. I have added a sub folder called 'Admin' under the 'Areas' folder and placed the relevant controllers and views in there in the appropriate subfolders.
I have then set up the routing as follows in Global.asax:
private 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[] { "AppName.Web.Controllers " });
routes.MapRoute(
"Admin",
"Admin/{controller}/{action}/{querydata}",
new { querydata = UrlParameter.Optional },
new[] { "AppName.Web.Areas.Admin.Controllers" });
}
Which is then called as below:
private void Application_Start(object sender, EventArgs e)
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
SecurityConfigurator.Configure(SecurityConfig.Configure);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
FilterConfig.RegisterGlobalApiFilters(GlobalConfiguration.Configuration.Filters);
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.DefaultNamespaces.Add("AppName.Web.Areas.Admin.Controllers");
}
If i then run the application, routing is working as expected in my area and the main application, apart from it seems to have broken the Login and LogOff methods in the aforementioned Home controller, now giving a 404 error when trying to access them. The index method of the same Home controller works fine though.
In case it's related to Fluentsecurity, this is how security is configured:
internal static void Configure(ConfigurationExpression configuration)
{
configuration.GetAuthenticationStatusFrom(() => HttpContext.Current.User.Identity.IsAuthenticated);
configuration.GetRolesFrom(GetRoles);
configuration.For<HomeController>(x => x.Login(default(string))).DenyAuthenticatedAccess();
configuration.For<HomeController>(x => x.Index()).DenyAnonymousAccess();
configuration.For<HomeController>(x => x.LogOff()).AllowAny();
//Admin Home
configuration.For<Areas.Admin.Controllers.HomeController>(x => x.Index()).DenyAnonymousAccess();
}
Any ideas where I may be going wrong?
private static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Admin",
"Admin/{controller}/{action}/{querydata}",
new { querydata = UrlParameter.Optional },
new[] { "AppName.Web.Areas.Admin.Controllers" });
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new[] { "AppName.Web.Controllers " });
}
Related
I have an asp.net web site that won't seem to resolve to Default.aspx when initially loading. When I debug on my local machine it loads Default no problem. Unless I try to navigate to "localhost:#####/". Then it gives a 404 error. When I deploy it to a staging server, give it a virtual path "mywebapp", and load it from "mydomain.com/mywebapp" it gives a 404 as well. I have set Default.aspx to the top of the list for Default Document in IIS. If I navigate to "mydomain.com/mywebapp/default" the site loads just fine. Any suggestions? I would paste code but it is a large website and I quite honestly am not sure what I'm looking for anymore.
EDIT:
In my site I am also using DataTables for display and edit of data. In the ajax calls I was previously able to call the controller by using urls such as:
api/MyController/idvalue
but since uncovering this I had to go back and preface the urls to get them to work:
mywebapp/api/MyController/idvalue
Controller:
public class MyController : ApiController
{
[Route("api/MyContoller/{idvalue}")]
[HttpGet]
[HttpPost]
public IHttpActionResult MyControllerMethod(intidvalue)
{
}
}
WebApiConfig:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
RouteConfig:
public static class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
var settings = new FriendlyUrlSettings();
settings.AutoRedirectMode = RedirectMode.Permanent;
routes.EnableFriendlyUrls(settings);
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//routes.MapRoute(
// name: "Default",
// url: "{controller}/{action}/{id}",
// defaults: new { action = "Index", id = UrlParameter.Optional }
// );
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
Found the solution. In my RouteConfig.cs if I comment out the line:
controller = "Home",
it works just fine.
public static class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
var settings = new FriendlyUrlSettings();
settings.AutoRedirectMode = RedirectMode.Permanent;
routes.EnableFriendlyUrls(settings);
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//routes.MapRoute(
// name: "Default",
// url: "{controller}/{action}/{id}",
// defaults: new { action = "Index", id = UrlParameter.Optional }
// );
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new
{
//controller = "Home",
action = "Index",
id = UrlParameter.Optional
}
);
}
}
However, I'm not completely sure why this is. So if anyone is able to explain it to me that would be great!
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 }
);
So I built a new ASP.NET MVC4 application, some really simple stuff. I added an Area for administration purposes. Everything works fine when I debug on Visual Studio's IIS Express.
The problem comes when I deploy this application on a Windows Server 2012's IIS, most of the time, when I try to acces my Area I get a 404 error. The weired thing is sometimes, after redeploying the application (but not changing anything), the area will work for a certain amount of time (until the application pool gets recycled maybe ?)
Anyway this is really weired and I'd need a hand on this. Here's what I've done :
Here is my RouteConfig for the base application :
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "NewsFilter",
url: "Articles/{tagName}",
defaults: new { controller = "Home", action = "Index", tagName = UrlParameter.Optional },
namespaces: new[] { "myapp.Controllers" }
);
routes.MapRoute(
"ViewArticle",
"Article/{articleId}/{articleTitle}",
new { controller = "Article", action = "Index", articleTitle = UrlParameter.Optional },
new { articleId = #"\d+" },
namespaces: new[] { "myapp.Controllers" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "myapp.Controllers" }
);
}
}
Now here's my AdminAreaRegistration for the Admin area
public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Admin";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
name: "Admin_default",
url: "Admin/Home/{action}/{id}",
defaults: new { controller="Home", action = "Index", id = UrlParameter.Optional },
namespaces: new []{ "myapp.Areas.Admin.Controllers" }
);
context.MapRoute(
name: "Admin_news",
url: "Admin/News/{action}/{id}",
defaults: new { controller="News", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "myapp.Areas.Admin.Controllers" }
);
context.MapRoute(
name: "Admin_Tags",
url: "Admin/Tags/{action}/{id}",
defaults: new { controller = "Tags", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "myapp.Areas.Admin.Controllers" }
);
}
}
Now here id the Application_Start method from Global.asax
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas(); //This registers the admin Area
WebApiConfig.Register(GlobalConfiguration.Configuration); //I did not delete WebApiConfig even though I'm not using it
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes); //And here are my "normal" routes
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
All the controllers from my Admin area are in the namespace myapp.Areas.Admin.Controllers. The main app controllers are in the namespace myapp.Controllers.
On IIS, the app pool for the application is running in .net 4.0 Integrated mode.
Any idea why the area is working in debug mode, working sometimes on IIS and returning 404 most of the time ?
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 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?