I have a C# .Net 4.5 Web Api application to which I have added a Help Page such as the one shown here.
When a developer launches the Web Api application in Visual Studio, I would like the help page to come up.
I would like to accomplish this by the using routing (such as a change to WebApiConfig.cs or Global.asax.cs) as opposed to a setting in the project's properties.
In the WebApiConfig.cs file I tried adding the following -
config.Routes.MapHttpRoute("Default", "api/help");
That did not work. Does anyone know how to make this work? Thanks.
Two years late, but for the benefit of Googlers like myself - A way to do it (based on this answer) is simply to modify the RegisterArea method in the HelpPageAreaRegistration.cs class in the HelpPage Area to contain a blank route. Example -
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"HelpPage_Default",
"Help/{action}/{apiId}",
new { controller = "Help", action = "Index", apiId = UrlParameter.Optional });
context.MapRoute(
"Help Area",
"",
new { controller = "Help", action = "Index" });
HelpPageConfig.Register(GlobalConfiguration.Configuration);
}
Related
I have a project that I am upgrading from MVC 2 -> MVC 4. During the transition from MVC 2 -> MVC 3, I noticed that some of my hyperlinks broke and were no longer matching the routes as defined before. I have the following project structure:
...
App_Data
Areas
Test
Controllers
TestController
Views
Models
Controllers
PartialController
Views
Scripts
...
The links that are generated are in the format /Test/Partial/Render. If I go back and run the project before the migration, the PartialController Render action is hit as expected. However, now the app says that it can't find an action because there is no Test/Partial controller. I actually am not sure how it worked before, but can't seem to get it to map correctly.
Is there something I'm missing? Here is the relevant code:
Global.asax.cs:
...
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
...
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = "" }
);
TestAreaRegistration.cs:
context.MapRoute(
"Test_default",
"Test/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
I did move the Controllers folder up a level to be more in-line with how the project should be structured; beforehand it was in the Areas folder itself. However, none of this worked before I moved that, so I doubt that is the case. I also thought that Autofac had something to do with this, but I am less certain of that because if I shave the "Test" portion out of the URL it matches as expected.
I guess this all boils down to a question on how to check in a "generic" controllers directory first, before matching to an area-specific controller directory, even with an area specified in the URL.
Thanks in advance for your help!
EDIT: If it helps, I noticed that in the existing MVC 2 solution, if I go to Test/Home for example, it will invoke the Index method of the HomeController. However, this does not happen in the new solution. Is this because there is no View associated with the new routes? I have not made new .cshtml files for each of the corresponding .ascx files yet, but I didn't think that should matter much as they are used otherwise.
So apparently the issue was related to namespaces. I had seen that answer on questions like this, but those had to do with collisions finding views. Here is the line I ended up adding to each of my Area registrations:
context.MapRoute(
"Test_default",
"Test/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new string[] { "Project.Web.Controllers", "Project.Web.Areas.Test.Controllers" } //added this line
);
I have a Controller with the name "Hem" and Action name is "Om".
And default language i have set Swedish.
So route will be on Swedish site, it's
/sv/Hem/Om
Now I want to change language to "en" by clicking English in language section.
So route will be set automatically like this way :
/en/Home/About
But functionality should be work of /sv/Hem/Om and In address bar should be display as /en/Home/About
Experts can you please help me out.
You can do this way.
routes.MapRoute(
"English route",
"en/{controller}/{action}/{id}"
new { controller = "Home", action = "Index", language = "en" },
);
routes.MapRoute(
"FrenchHome",
"/sv/Hem/Om",
new { controller = "Home", action = "Index", language = "fr" }
);
or you can do that way:
public class GenericRoutes
{
public string Controller {get;set;}
public string Action {get;set;}
public string Url{get;set;}
public string RouteName{get;set;}
}
public List<GenericRoutes> Routes = new List<GenericRoutes>();
Routes.Add(new GenericRoutes{Cotroller="bl",Action="cl",Url="bl/cl"})
for(int i=0;i<Routes.count();i++)
{
routes.MapRoute(
Routes[i].RouteName,
Routes[i].Url,
new { controller = Routes[i].Controller, action = Routes[i].Action },
);
}
I personally would avoid this approach for multilingual sites. Yes it is technically possible to do what you are asking but most sites do not handle multiple languages in this way. ASP.net has had ability to localize pages for a long time and I would recommend this approach instead.
Localization involves putting resource keys in your view template instead of hard coding your strings. Then you would set the culture of your thread, usually by the http accept-language header and the site would chose the appropriate strings for that culture to put into the page view. The only thing you need to maintain then is sets of strings for each language.
The benefit for this approach is that you write your views only once. When you have 2 or even 3 sets of views you run the risk of having those versions of your site diverge. I personally have seen this happen and its a hard problem to get back from. Also you get to separate your "language problem" from whatever problem your website is solving, meaning your domain isn't cluttered with boilerplate code to maintain a fancy language switching technique, instead of going with the solution that's included with the platform.
If you are interested in doing multi-language sites in .net the right way I would recommend learning about Localization and Globalization, here is a good place to start :)
Beginners Tutorial
Scott Hanselman tutorial - MVC 3 + Jquery version
First of all, I am not an expert. But in order to route user to different controller you can implement custom routing and configure routes dynamically.
To understand how routing works you may consider checking this link out.
Here is a quick trick to do that:
Here is RegisterRoutes method which register all routes for application
public static void RegisterRoutes(RouteCollection routes)
{}
now get current language from url(get first segment of url (en in your case))
query your data source for current language
add your routes here from database or any other source using foreach.
.
foreach (var route in RouteValues)
{
route.UniqueName,
routes.MapRoute("prefix/{controller}/{action}/{id},
new { controller = route.Controller , action = route.Action , id = route.Id });
}
TL;DR
I need a way to programtically choose which RoutePrefix is chosen when generating URLs based on the properties of a user in my MVC app
Not TL;DR
I have an MVC 4 app (with the AttributeRouting NuGet package)
Due to the requirements of the hosting environment I have to have two routes for a lot of my actions so that the hosting environment can have different permissions for access.
I am solving this by decorating my controller with with [RoutePrefix("full")] [RoutePrefix("lite)]. which allows each action method to be accessed via /full/{action} and /lite/{action}.
This works perfectly.
[RoutePrefix("full")]
[RoutePrefix("lite")]
public class ResultsController : BaseController
{
// Can be accessed via /full/results/your-results and /lite/results/your-results and
[Route("results/your-results")]
public async Task<ActionResult> All()
{
}
}
However, each user should only use either full or lite in their urls, which is determined by some properties of that user.
Obviously when I use RedirectToAction() or #Html.ActionLink() it will just choose the first available route and won't keep the "correct" prefix.
I figured I can override the RedirectToAction() method as well as add my own version of #Html.ActionLink() methods.
This will work, but it will involve some nasty code for me to generate the URLs because all I get is a string representing the action and controllers, but not the reflected types. Also there might be route attributes such as in my example, so I am going to have to replicated a lot of MVCs built in code.
Is there a better solution to the problem I am trying to solve?
How about something like:
[RoutePrefix("{version:regex(^full|lite$)}")]
Then, when you create your links:
#Url.RouteUrl("SomeRoute", new { version = "full" })
Or
#Url.RouteUrl("SomeRoute", new { version = "lite" })
You could even do the following to just keep whatever was already set:
#Url.RouteUrl("SomeRoute", new { version = Request["version"] })
I ended up finding a solution to this
I just overrided the default routes to include this. ASP.Net automatically keeps the usertype value and puts it back in when it regenerates the routes
const string userTypeRegex = "^(full|lite)$";
routes.Add("Default", new Route("{usertype}/{controller}/{action}/{id}",
new { controller = "Sessions", action = "Login", id = UrlParameter.Optional }, new { usertype = userTypeRegex }));
I found that this didn't work with the Route or RoutePrefix attributes, and so I had to remove all of them. Forcing me to add specific routes in these cases
routes.Add("Profile-Simple", new Route("{usertype}/profile/simple",
new { controller = "ProfileSimple", action = "Index" }, new { usertype = userTypeRegex }));
I thought that a half-dozen hard coded routes in my RouteConfig file was a better solution than having to manually add values to each place I generated a URL (as in Chris's solution).
I have added the following code
public class RouteController : Controller
{
public ContentResult GetImpression()
{
// Do something
}
}
In RouteConfig class i have added the following
routes.MapRoute(
name: "Impression",
url: "imp",
defaults: new { controller = "Route", action = "GetImpression", id = UrlParameter.Optional }
);
I am expecting my http://mymachine/imp to work. What am i doing wrong? Do i have to do some settings in IIS as well?
For issues with routing I have always found the following tool from Phil Hacck to be invaluable in figuring out where I screwed up with my routing rules and what is getting called. There is nothing special you need to do in IIS to get things working. The one thing you probably should check is to ensure if your Application Pool is using version 4.0 and not version 2.0. Usually when you create a site in IIS it defaults the App Pool to 2.0.
I'm having some issues getting Areas working correctly within MVC 3. I have the following folder structure and an Admin area set up:
I'm trying to navigate from the admin page (Index) to the the other view pages in the Admin area for example Admin/Floor/Create etc... but I get The resource cannot be found error on every url combination i've tried for example:
#Html.ActionLink("floors", "Index", "Floor", new { area = "Admin" }, null)
/Floor/Index/
/Admin/Floor/Index/
None of which work. I managed to use the first ActionLink one to link to the admin index page from outside of the area but it's no use here.
The area registration looks like this:
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
Can anyone offer some help?
Thankyou
The problem is with your routing. You need to set the default controller to be AdminController:
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { controller = "Admin", action = "Index", id = UrlParameter.Optional }
);
If you don't specify this, MVC doesn't know quite what you're looking for and actually expects you to navigate to /admin/admin in order to display the initial view. So change the routing as I've mentioned above and then use this action link to get to FloorController.Create():
#Html.ActionLink("floors", "create", "floor", new { area = "admin" }, null)
To expand a little, with your routing setup this way, your URLs will look like this:
/admin // Executes AdminController.Index()
/admin/floor // Executes FloorController.Index()
Update
Having downloaded Maciej RogoziĆski's project, this gives me the same problem that your project currently has. The link from the default action is linking to /admin/admin/, which as I mentioned earlier, is what your project is looking for because no default controller has been specified for the area routing (this also applies to Maciej's project). Specifying the default controller allows you to navigate to /admin, which results in AdminController.Index() being invoked. Without specifying that controller, you can only retrieve this view from routing to /admin/admin, which again, is what Maciej's application is doing.