I know how to send data to controller's action method as parameter from URL. Here I wonder how can I send data from URL to controller's field?
public MyAwesomeController : Controller {
public string SectionCode { get;set; }
}
and let's define Routes :
routes.MapRoute(
name : "AwesomeRouter",
url : "{code}/{action}",
defaults: new {controller = "MyAwesome", action = "Index", /* What to do here?*/}
);
I want SectionCode be filled with the {code} from URL. Is it possible to implement?
Yes it is, you can create inherited class from basic Controller class and override OnActionExecuting method where you can read url, route or any form data and store them in session or directly fill any field you need. Then create an inherited class of your controller.
public class MyAwesomeController : MyControllerBase
{
public ActionResult Index()
{
//this.SectionCode is available populated here
return View();
}
}
public class MyControllerBase : Controller
{
public string SectionCode
{
get;
private set;
}
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
this.SectionCode = filterContext.RequestContext.RouteData.Values["code"].ToString();
base.OnActionExecuting(filterContext);
}
}
Each time you hit any action in this controller using route definition you provided, field will be automatically populated. But when you will have more than one route defined they it could get easily into conflicts eg. when code will match to any controller name. Normal website should not work this way.
Your route should look like this:
routes.MapRoute(
name: "AwesomeRouter",
url: "{code}/{action}",
defaults: new { controller = "MyAwesome", action = "Index" }
);
The code should then be passed on to the action as a parameter. I am storing it in the view bag for explanation purposes:
public class MyAwesomeController : Controller
{
public ActionResult Index(string code)
{
ViewBag.Code = code;
return View();
}
}
Using this URL then:
http://somehost/4567/Index
If you access the Viewbag property in your view:
#ViewBag.Code
You should see:
4567
Related
I am creating a project in C# MVC and was using actions. Due to the requirements, now I am using Route to hide the controller name and display just the page name.
route config
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Law",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Law", action = "Home", id = UrlParameter.Optional }
);
controller 1 (to access this : http://localhost:17920/dashboard) and (http://localhost:17920/alert)
public class LawController : Controller
{
[Route("dashboard")]
[ActionName("Home")]
public ActionResult Home()
{
return View();
}
[Route("alert")]
[ActionName("alert-list")]
public ActionResult AlertList()
{
return View();
}
controller 2 (to access this : http://localhost:17920/list)
public class ListController : Controller
{
[Route("list")]
[ActionName("list-of-return")]
public ActionResult listOfReturn()
{
return View();
}
What I am trying is when I enter this http://localhost:17920 as a default URL, then http://localhost:17920/dashboard should be displayed by default.
Thanks.
You need to define RoutePrefix over the Controller like below. Also update your Route("dashboard") to Route("Home") because that is your default action name on route configuration.
[RoutePrefix("Law")]
public class LawController : Controller
{
[Route("Home")]
[ActionName("Home")]
public ActionResult Home()
{
return View();
}
// Other action methods
}
Please also refer https://devblogs.microsoft.com/aspnet/attribute-routing-in-asp-net-mvc-5/ for more details.
Edit As per edit in your question it is more clear what you want. From your existing code you just need to add one more Route over LawController's Home action as below, so it could match http://localhost:17920/ & http://localhost:17920/dashboard to that action method.
public class LawController : Controller
{
[Route("")]
[Route("dashboard")]
[ActionName("Home")]
public ActionResult Home()
{
return View();
}
[Route("alert")]
[ActionName("alert-list")]
public ActionResult AlertList()
{
return View();
}
I have an api using web api 2 and I am trying to create help docs within an Area so that an incoming request like ...api/people.help will route to the people controller and people view and serve up the html. I am struggling with the route mapping for the area after refactoring the code. Previously, I had routes like this:
public override void RegisterArea(AreaRegistrationContext context) {
context.MapRoute(
name: "Help",
url: "{action}.help",
defaults: new { area = "help", controller = "default" }
);
All the methods were in the default controller and this worked. Now, I need a separate controller for each resource (eg people, schedules etc) but can't get the routes to work. I would appreciate help, I am very new to this. How do I get each help request to map to the controller with the same action name?
Wouldn't it simply be something similar to:
public override RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
name: "Help",
url: "api/{controller}.help",
defaults: new { area = "help" }
);
}
What you have in your post is a default for the name of the controller, in this case, it's name will always be default. Instead, what you're looking for is that when someone routes to your controller name suffixed with .help, it'll route to a path akin to api/help/people, which will end up calling a default action (in MVC) such as index.cshtml or the default action for a GET request to the controller (for WebAPI).
So, you want to set the default area to help as shown above. You also want to set the default action that should execute on the provided controller.
Update: To answer question in comment
For MVC, you can have an action method whose name matches what the controller name will be in the URL:
public class PeopleController : Controller
{
[HttpGet] // Not strictly necessary, but just want to stress this is GET
public ActionResult People()
{
// Do stuff in your action method
}
}
The only problem is, your action method will be different for each controller, and so unknowable for route registration purposes. Therefore, you should maybe have just a default Help action:
public class PeopleController : Controller
{
[HttpGet]
public ActionResult Help()
{
// Do stuff
}
}
Then you can have the following route:
public override RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
name: "Help",
url: "api/{controller}.help",
defaults: new { area = "help", action = "Help" }
}
You could take this one step further and provide a Help method in a custom base controller class:
public class MyBaseController : Controller
{
public virtual ActionResult Help()
{
// Do default behavior stuff, if appropriate
}
// If you don't have any "default" behavior, you could make the method abstract:
// public abstract ActionResult Help();
}
public class PeopleController : MyBaseController
{
public override ActionResult Help()
{
// Do stuff.
}
}
Update to further answer OP's question in comments
So, now the OP is saying: "but I want my view to have the same name as my controller." Ok, that should be no problem:
public class PeopleController : MyBaseController // if you're using a base class
{
public override ActionResult Help()
{
return ViewResult("People");
}
}
So, you can have a view with any name you want. But if the view's name differs from the name of the action method, then when returning (say) a ViewResult, you'll need to specify the name of the view to return.
Having said all that, the default folder structure for views in ASP.Net is Areas/{AreaName}/Views/{Controller}/{viewname}.{cs|vb}html. And here, {viewname} is by default assumed to be the action method name, but doesn't have to be when, as above, explicitly telling MVC which view to return (in the example above, People.cshtml).
HTH.
This controller:
public class TestController <T> : Controller
{
public string Index()
{
return "123";
}
}
This definition of the routes:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new
{
controller = "Test<T>",
action = "Index",
id = ""
});
This is the error I get:
The IControllerFactory 'Yad2.Web.Mvc.UI.Infrastructure.NinjectControllerFactory' did not return a controller for the name 'Test'.
public class TestController <T> : Controller
{
public string Index( )
{
return "123";
}
}
List of things wrong here:
Controllers cannot be generic abstract classes, you need to define T.
All actions need to return ActionResult derived objects.
"Test" in your route definition is absolutely incorrect. Never going to work.
You never showed your Ninject registration.
I'm having trouble adding a URL parameter to every URL generated, or redirected to in an ASP MVC 4 application.
I want to generate an ID, and use this ID at any point throughout the application. Storing the id in session is not an option as a single session may have multiple browser windows/tabs open concurrently (each with a different id)
RouteConfig
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{customId}",
defaults: new { controller = "Home", action = "Index", customid = UrlParameter.Optional }
);
HomeController.cs
public class HomeController : Controller
{
public ActionResult Index()
{
var customId = Guid.NewGuid();
ControllerContext.RequestContext.RouteData.Values.Add("customId", customId);
//How do I get this redirect to add customid to the url?
//E.g. /Home/Start/{customId}
return RedirectToAction("Start");
//I could do this: But I want it this to happen for every URL,
//and I don't want to replicate this code everywhere
//return RedirectToAction("Start", new { customId = customId });
}
public ActionResult Start()
{
object customId;
//Redirect Loop
if (!Request.RequestContext.RouteData.Values.TryGetValue("customId", out customId))
{
//To generate the ID
return RedirectToAction("Index");
}
ViewData["customId"] = Guid.Parse(customId.ToString());
return View();
}
public ActionResult Next()
{
object customId;
//Redirect Loop
if (!Request.RequestContext.RouteData.Values.TryGetValue("customId", out customId))
{
//To generate the ID
return RedirectToAction("Index");
}
ViewData["customId"] = Guid.Parse(customId.ToString());
return View();
}
}
Not only do I want the ID to be automatically inserted into any Redirect results, but when a View is rendered #Url.Action() and #Html.ActionLink() should also add the ID to the generated URL's.
Start.cshtml
#*Both of these should generate an href="~/Home/Next/{customId}"*#
#Html.ActionLink("Go to Next", "Next", "Home")
Go to Next
How do I automatically add an ID to ALL outgoing routes in ASP MVC?
Create an action filter that will add the ID to the route data in the OnActionExecuting method? You can access the controller through the filter context (and the viewbag). As long as your viewbag contains the customId, you should be able to add it to the route data. At least this way you only need to remember to add the attribute on the controller.
OR
Create a base class that inherits from System.Web.Mvc.Controller and implement your own RedirectToAction. Then have all your controllers inherit form MyControllerBase. Something like this.
public class MyControllerBase : Controller
{
public RedirectToRouteResult RedirectToAction<TController>(Expression<Func<TController, object>> actionExpression)
{
var custId = ControllerContext.Controller.ViewBag["customId"];
string controllerName = typeof(TController).GetControllerName();
string actionName = actionExpression.GetActionName();
return RedirectToAction(actionName, controllerName, new {cId = custId});
}
}
PART 2:
Another way I've modified a URL (I knew I had the code somewhere!) on every view, I needed the URL to link from a mobile site to a full browser site and read the mappings from the database. So in my footer, I have the following:
<a id="fullSiteLink" href="<%= ViewData[AppConstants.MainSiteUrl] %>">Visit our Full Browser site</a><br />
I then added a filter to the base controller class and onactionexecuting (before the action),
public void OnActionExecuting(ActionExecutingContext filterContext)
{
var mainSiteUrl = _mobileToMainRedirect.GetMainSiteUrl(filterContext.HttpContext.Request.Url);
filterContext.Controller.ViewData.Add(AppConstants.MainSiteUrl, string.IsNullOrEmpty(mainSiteUrl) ? UrlHelperExtensions.FullBrowserSite(filterContext.HttpContext.Request.Url) : mainSiteUrl);
}
Complete shot in the dark....
You can set up the route so that if a value is not provided, you create the Id. This way, if the value is there, it will use the provided one. Otherwise, it will create one.
Since this is leveraging the routes, you will be able to generate the Id even when using:
#Html.ActionLink("Go to Next", "Next", "Home")
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{customid}",
defaults: new { controller = "Home", action = "Index", customid = Guid.NewGuid() }
);
NOTE: You would replace Guid.NewGuid() with your own Id generator.
iam having controller like below which is not registered in routes table
public class InternalController : Controller
{
/*this controller is not registered in routes table*/
public ActionResult Foo()
{
return Content("Text from foo");
}
}
From another controller which is registered in Routes table i want to call/redirect action of previous controller, one which is not registered in routes table.
public class AjaxController : Controller
{
/*this controller is registered in routes table*/
public ActionResult Foo()
{
/*FROM HERE HOW DO I RETURN CONTENTS OF
controller=InternalController, action = Foo
*/
/*
i tried below piece of code but that doesnt seem to work
*/
return RedirectToAction("Foo", "InternalController ");
}
}
Defined Routes (only one item added)
public void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute("Ajax","ajax/{action}",new {
controller="Ajax",
action="Index"
});
}
If you are choosing not to register a route... then you probably have the file/controller in a specific location that will not change.
In that event, just use the "Redirect" method, instead of "RedirectToAction".
For example:
return Redirect("~/Internal/Foo");
Now that you have shown your routes definition, it is obvious that you can never invoke any other controller than AjaxController. You simply forbid them in your routes, so InternalController could never be served. You will have to change your route definition.
Depending on what you want to achieve and how you want your urls to look like you have a couple of possibilities:
Leave the default route
Modify your existing route definition like so:
routes.MapRoute(
"Ajax",
"{controller}/{action}",
new { controller = "Ajax", action = "Index" }
);
You can create RedirectController for redirecting more Url and pages:
public class RedirectController : Controller
{
public ActionResult Index()
{
var rd = this.RouteData.Values;
string controller = rd["controller2"] as string;
string action = rd["action2"] as string;
rd.Remove("controller2");
rd.Remove("action2");
rd.Remove("controller");
rd.Remove("action");
return RedirectToActionPermanent(action, controller, rd);
}
}
And then you can define redirect from old url in routing tables:
routes.MapRoute(
null, // Name
"ajax/foo",
new { controller = "Redirect",
action = "Index",
controller2 = "InternalController",
action2 = "Foo"}
);
This pattern is also useful if you redirect old url to new one. For example:
routes.MapRoute(
null, // Name
"default.aspx", // redirect from old ASP.NET
new { controller = "Redirect",
action = "Index",
controller2 = "Home",
action2 = "Index" }
);